1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
18
#include "apr_strings.h"
20
#define APR_WANT_STDIO /* for sprintf() */
21
#define APR_WANT_STRFUNC
26
#include "apu_config.h"
28
#ifdef APR_HAVE_OLD_EXPAT
34
#define DEBUG_CR "\r\n"
36
static const char APR_KW_xmlns[] = { 0x78, 0x6D, 0x6C, 0x6E, 0x73, '\0' };
37
static const char APR_KW_xmlns_lang[] = { 0x78, 0x6D, 0x6C, 0x3A, 0x6C, 0x61, 0x6E, 0x67, '\0' };
38
static const char APR_KW_DAV[] = { 0x44, 0x41, 0x56, 0x3A, '\0' };
40
/* errors related to namespace processing */
41
#define APR_XML_NS_ERROR_UNKNOWN_PREFIX (-1000)
42
#define APR_XML_NS_ERROR_INVALID_DECL (-1001)
44
/* test for a namespace prefix that begins with [Xx][Mm][Ll] */
45
#define APR_XML_NS_IS_RESERVED(name) \
46
( (name[0] == 0x58 || name[0] == 0x78) && \
47
(name[1] == 0x4D || name[1] == 0x6D) && \
48
(name[2] == 0x4C || name[2] == 0x6C) )
51
/* the real (internal) definition of the parser context */
52
struct apr_xml_parser {
53
apr_xml_doc *doc; /* the doc we're parsing */
54
apr_pool_t *p; /* the pool we allocate from */
55
apr_xml_elem *cur_elem; /* current element */
57
int error; /* an error has occurred */
58
#define APR_XML_ERROR_EXPAT 1
59
#define APR_XML_ERROR_PARSE_DONE 2
60
/* also: public APR_XML_NS_ERROR_* values (if any) */
62
XML_Parser xp; /* the actual (Expat) XML parser */
63
enum XML_Error xp_err; /* stored Expat error code */
66
/* struct for scoping namespace declarations */
67
typedef struct apr_xml_ns_scope {
68
const char *prefix; /* prefix used for this ns */
69
int ns; /* index into namespace table */
70
int emptyURI; /* the namespace URI is the empty string */
71
struct apr_xml_ns_scope *next; /* next scoped namespace */
75
/* return namespace table index for a given prefix */
76
static int find_prefix(apr_xml_parser *parser, const char *prefix)
78
apr_xml_elem *elem = parser->cur_elem;
81
** Walk up the tree, looking for a namespace scope that defines this
84
for (; elem; elem = elem->parent) {
85
apr_xml_ns_scope *ns_scope = elem->ns_scope;
87
for (ns_scope = elem->ns_scope; ns_scope; ns_scope = ns_scope->next) {
88
if (strcmp(prefix, ns_scope->prefix) == 0) {
89
if (ns_scope->emptyURI) {
91
** It is possible to set the default namespace to an
92
** empty URI string; this resets the default namespace
93
** to mean "no namespace." We just found the prefix
94
** refers to an empty URI, so return "no namespace."
96
return APR_XML_NS_NONE;
105
* If the prefix is empty (""), this means that a prefix was not
106
* specified in the element/attribute. The search that was performed
107
* just above did not locate a default namespace URI (which is stored
108
* into ns_scope with an empty prefix). This means the element/attribute
109
* has "no namespace". We have a reserved value for this.
111
if (*prefix == '\0') {
112
return APR_XML_NS_NONE;
116
return APR_XML_NS_ERROR_UNKNOWN_PREFIX;
119
static void start_handler(void *userdata, const char *name, const char **attrs)
121
apr_xml_parser *parser = userdata;
129
/* punt once we find an error */
133
elem = apr_pcalloc(parser->p, sizeof(*elem));
135
/* prep the element */
136
elem->name = elem_name = apr_pstrdup(parser->p, name);
138
/* fill in the attributes (note: ends up in reverse order) */
140
attr = apr_palloc(parser->p, sizeof(*attr));
141
attr->name = apr_pstrdup(parser->p, *attrs++);
142
attr->value = apr_pstrdup(parser->p, *attrs++);
143
attr->next = elem->attr;
147
/* hook the element into the tree */
148
if (parser->cur_elem == NULL) {
149
/* no current element; this also becomes the root */
150
parser->cur_elem = parser->doc->root = elem;
153
/* this element appeared within the current elem */
154
elem->parent = parser->cur_elem;
156
/* set up the child/sibling links */
157
if (elem->parent->last_child == NULL) {
158
/* no first child either */
159
elem->parent->first_child = elem->parent->last_child = elem;
162
/* hook onto the end of the parent's children */
163
elem->parent->last_child->next = elem;
164
elem->parent->last_child = elem;
167
/* this element is now the current element */
168
parser->cur_elem = elem;
171
/* scan the attributes for namespace declarations */
172
for (prev = NULL, attr = elem->attr;
175
if (strncmp(attr->name, APR_KW_xmlns, 5) == 0) {
176
const char *prefix = &attr->name[5];
177
apr_xml_ns_scope *ns_scope;
179
/* test for xmlns:foo= form and xmlns= form */
180
if (*prefix == 0x3A) {
181
/* a namespace prefix declaration must have a
183
if (attr->value[0] == '\0') {
184
parser->error = APR_XML_NS_ERROR_INVALID_DECL;
189
else if (*prefix != '\0') {
190
/* advance "prev" since "attr" is still present */
195
/* quote the URI before we ever start working with it */
196
quoted = apr_xml_quote_string(parser->p, attr->value, 1);
198
/* build and insert the new scope */
199
ns_scope = apr_pcalloc(parser->p, sizeof(*ns_scope));
200
ns_scope->prefix = prefix;
201
ns_scope->ns = apr_xml_insert_uri(parser->doc->namespaces, quoted);
202
ns_scope->emptyURI = *quoted == '\0';
203
ns_scope->next = elem->ns_scope;
204
elem->ns_scope = ns_scope;
206
/* remove this attribute from the element */
208
elem->attr = attr->next;
210
prev->next = attr->next;
212
/* Note: prev will not be advanced since we just removed "attr" */
214
else if (strcmp(attr->name, APR_KW_xmlns_lang) == 0) {
215
/* save away the language (in quoted form) */
216
elem->lang = apr_xml_quote_string(parser->p, attr->value, 1);
218
/* remove this attribute from the element */
220
elem->attr = attr->next;
222
prev->next = attr->next;
224
/* Note: prev will not be advanced since we just removed "attr" */
227
/* advance "prev" since "attr" is still present */
233
** If an xml:lang attribute didn't exist (lang==NULL), then copy the
234
** language from the parent element (if present).
236
** NOTE: elem_size() *depends* upon this pointer equality.
238
if (elem->lang == NULL && elem->parent != NULL)
239
elem->lang = elem->parent->lang;
241
/* adjust the element's namespace */
242
colon = strchr(elem_name, 0x3A);
245
* The element is using the default namespace, which will always
246
* be found. Either it will be "no namespace", or a default
247
* namespace URI has been specified at some point.
249
elem->ns = find_prefix(parser, "");
251
else if (APR_XML_NS_IS_RESERVED(elem->name)) {
252
elem->ns = APR_XML_NS_NONE;
256
elem->ns = find_prefix(parser, elem->name);
257
elem->name = colon + 1;
259
if (APR_XML_NS_IS_ERROR(elem->ns)) {
260
parser->error = elem->ns;
265
/* adjust all remaining attributes' namespaces */
266
for (attr = elem->attr; attr; attr = attr->next) {
268
* apr_xml_attr defines this as "const" but we dup'd it, so we
269
* know that we can change it. a bit hacky, but the existing
270
* structure def is best.
272
char *attr_name = (char *)attr->name;
274
colon = strchr(attr_name, 0x3A);
277
* Attributes do NOT use the default namespace. Therefore,
278
* we place them into the "no namespace" category.
280
attr->ns = APR_XML_NS_NONE;
282
else if (APR_XML_NS_IS_RESERVED(attr->name)) {
283
attr->ns = APR_XML_NS_NONE;
287
attr->ns = find_prefix(parser, attr->name);
288
attr->name = colon + 1;
290
if (APR_XML_NS_IS_ERROR(attr->ns)) {
291
parser->error = attr->ns;
298
static void end_handler(void *userdata, const char *name)
300
apr_xml_parser *parser = userdata;
302
/* punt once we find an error */
306
/* pop up one level */
307
parser->cur_elem = parser->cur_elem->parent;
310
static void cdata_handler(void *userdata, const char *data, int len)
312
apr_xml_parser *parser = userdata;
314
apr_text_header *hdr;
317
/* punt once we find an error */
321
elem = parser->cur_elem;
322
s = apr_pstrndup(parser->p, data, len);
324
if (elem->last_child == NULL) {
325
/* no children yet. this cdata follows the start tag */
326
hdr = &elem->first_cdata;
329
/* child elements exist. this cdata follows the last child. */
330
hdr = &elem->last_child->following_cdata;
333
apr_text_append(parser->p, hdr, s);
336
static apr_status_t cleanup_parser(void *ctx)
338
apr_xml_parser *parser = ctx;
340
XML_ParserFree(parser->xp);
346
APU_DECLARE(apr_xml_parser *) apr_xml_parser_create(apr_pool_t *pool)
348
apr_xml_parser *parser = apr_pcalloc(pool, sizeof(*parser));
351
parser->doc = apr_pcalloc(pool, sizeof(*parser->doc));
353
parser->doc->namespaces = apr_array_make(pool, 5, sizeof(const char *));
355
/* ### is there a way to avoid hard-coding this? */
356
apr_xml_insert_uri(parser->doc->namespaces, APR_KW_DAV);
358
parser->xp = XML_ParserCreate(NULL);
359
if (parser->xp == NULL) {
360
(*apr_pool_abort_get(pool))(APR_ENOMEM);
364
apr_pool_cleanup_register(pool, parser, cleanup_parser,
365
apr_pool_cleanup_null);
367
XML_SetUserData(parser->xp, parser);
368
XML_SetElementHandler(parser->xp, start_handler, end_handler);
369
XML_SetCharacterDataHandler(parser->xp, cdata_handler);
374
static apr_status_t do_parse(apr_xml_parser *parser,
375
const char *data, apr_size_t len,
378
if (parser->xp == NULL) {
379
parser->error = APR_XML_ERROR_PARSE_DONE;
382
int rv = XML_Parse(parser->xp, data, len, is_final);
385
parser->error = APR_XML_ERROR_EXPAT;
386
parser->xp_err = XML_GetErrorCode(parser->xp);
390
/* ### better error code? */
391
return parser->error ? APR_EGENERAL : APR_SUCCESS;
394
APU_DECLARE(apr_status_t) apr_xml_parser_feed(apr_xml_parser *parser,
398
return do_parse(parser, data, len, 0 /* is_final */);
401
APU_DECLARE(apr_status_t) apr_xml_parser_done(apr_xml_parser *parser,
405
apr_status_t status = do_parse(parser, &end, 0, 1 /* is_final */);
407
/* get rid of the parser */
408
(void) apr_pool_cleanup_run(parser->p, parser, cleanup_parser);
418
APU_DECLARE(char *) apr_xml_parser_geterror(apr_xml_parser *parser,
420
apr_size_t errbufsize)
422
int error = parser->error;
425
/* clear our record of an error */
433
case APR_XML_NS_ERROR_UNKNOWN_PREFIX:
434
msg = "An undefined namespace prefix was used.";
437
case APR_XML_NS_ERROR_INVALID_DECL:
438
msg = "A namespace prefix was defined with an empty URI.";
441
case APR_XML_ERROR_EXPAT:
442
(void) apr_snprintf(errbuf, errbufsize,
443
"XML parser error code: %s (%d)",
444
XML_ErrorString(parser->xp_err), parser->xp_err);
447
case APR_XML_ERROR_PARSE_DONE:
448
msg = "The parser is not active.";
452
msg = "There was an unknown error within the XML body.";
456
(void) apr_cpystrn(errbuf, msg, errbufsize);
460
APU_DECLARE(apr_status_t) apr_xml_parse_file(apr_pool_t *p,
461
apr_xml_parser **parser,
464
apr_size_t buffer_length)
470
*parser = apr_xml_parser_create(p);
471
if (*parser == NULL) {
472
/* FIXME: returning an error code would be nice,
473
* but we dont get one ;( */
476
buffer = apr_palloc(p, buffer_length);
477
length = buffer_length;
479
rv = apr_file_read(xmlfd, buffer, &length);
481
while (rv == APR_SUCCESS) {
482
rv = apr_xml_parser_feed(*parser, buffer, length);
483
if (rv != APR_SUCCESS) {
487
length = buffer_length;
488
rv = apr_file_read(xmlfd, buffer, &length);
493
rv = apr_xml_parser_done(*parser, ppdoc);
498
APU_DECLARE(void) apr_text_append(apr_pool_t * p, apr_text_header *hdr,
501
apr_text *t = apr_palloc(p, sizeof(*t));
506
if (hdr->first == NULL) {
507
/* no text elements yet */
508
hdr->first = hdr->last = t;
511
/* append to the last text element */
518
/* ---------------------------------------------------------------
520
** XML UTILITY FUNCTIONS
524
** apr_xml_quote_string: quote an XML string
526
** Replace '<', '>', and '&' with '<', '>', and '&'.
527
** If quotes is true, then replace '"' with '"'.
529
** quotes is typically set to true for XML strings that will occur within
530
** double quotes -- attribute values.
532
APU_DECLARE(const char *) apr_xml_quote_string(apr_pool_t *p, const char *s,
537
apr_size_t extra = 0;
542
for (scan = s; (c = *scan) != '\0'; ++scan, ++len) {
543
if (c == '<' || c == '>')
544
extra += 3; /* < or > */
546
extra += 4; /* & */
547
else if (quotes && c == '"')
548
extra += 5; /* " */
555
qstr = apr_palloc(p, len + extra + 1);
556
for (scan = s, qscan = qstr; (c = *scan) != '\0'; ++scan) {
576
else if (quotes && c == '"') {
593
/* how many characters for the given integer? */
594
#define APR_XML_NS_LEN(ns) ((ns) < 10 ? 1 : (ns) < 100 ? 2 : (ns) < 1000 ? 3 : \
595
(ns) < 10000 ? 4 : (ns) < 100000 ? 5 : \
596
(ns) < 1000000 ? 6 : (ns) < 10000000 ? 7 : \
597
(ns) < 100000000 ? 8 : (ns) < 1000000000 ? 9 : 10)
599
static apr_size_t text_size(const apr_text *t)
603
for (; t; t = t->next)
604
size += strlen(t->text);
608
static apr_size_t elem_size(const apr_xml_elem *elem, int style,
609
apr_array_header_t *namespaces, int *ns_map)
613
if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
614
const apr_xml_attr *attr;
618
if (style == APR_XML_X2T_FULL_NS_LANG) {
622
** The outer element will contain xmlns:ns%d="%s" attributes
623
** and an xml:lang attribute, if applicable.
626
for (i = namespaces->nelts; i--;) {
627
/* compute size of: ' xmlns:ns%d="%s"' */
628
size += (9 + APR_XML_NS_LEN(i) + 2 +
629
strlen(APR_XML_GET_URI_ITEM(namespaces, i)) + 1);
632
if (elem->lang != NULL) {
633
/* compute size of: ' xml:lang="%s"' */
634
size += 11 + strlen(elem->lang) + 1;
638
if (elem->ns == APR_XML_NS_NONE) {
639
/* compute size of: <%s> */
640
size += 1 + strlen(elem->name) + 1;
643
int ns = ns_map ? ns_map[elem->ns] : elem->ns;
645
/* compute size of: <ns%d:%s> */
646
size += 3 + APR_XML_NS_LEN(ns) + 1 + strlen(elem->name) + 1;
649
if (APR_XML_ELEM_IS_EMPTY(elem)) {
650
/* insert a closing "/" */
655
* two of above plus "/":
656
* <ns%d:%s> ... </ns%d:%s>
662
for (attr = elem->attr; attr; attr = attr->next) {
663
if (attr->ns == APR_XML_NS_NONE) {
664
/* compute size of: ' %s="%s"' */
665
size += 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1;
668
/* compute size of: ' ns%d:%s="%s"' */
669
size += 3 + APR_XML_NS_LEN(attr->ns) + 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1;
674
** If the element has an xml:lang value that is *different* from
675
** its parent, then add the thing in: ' xml:lang="%s"'.
677
** NOTE: we take advantage of the pointer equality established by
678
** the parsing for "inheriting" the xml:lang values from parents.
680
if (elem->lang != NULL &&
681
(elem->parent == NULL || elem->lang != elem->parent->lang)) {
682
size += 11 + strlen(elem->lang) + 1;
685
else if (style == APR_XML_X2T_LANG_INNER) {
687
* This style prepends the xml:lang value plus a null terminator.
688
* If a lang value is not present, then we insert a null term.
690
size = elem->lang ? strlen(elem->lang) + 1 : 1;
695
size += text_size(elem->first_cdata.first);
697
for (elem = elem->first_child; elem; elem = elem->next) {
698
/* the size of the child element plus the CDATA that follows it */
699
size += (elem_size(elem, APR_XML_X2T_FULL, NULL, ns_map) +
700
text_size(elem->following_cdata.first));
706
static char *write_text(char *s, const apr_text *t)
708
for (; t; t = t->next) {
709
apr_size_t len = strlen(t->text);
710
memcpy(s, t->text, len);
716
static char *write_elem(char *s, const apr_xml_elem *elem, int style,
717
apr_array_header_t *namespaces, int *ns_map)
719
const apr_xml_elem *child;
723
if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
724
int empty = APR_XML_ELEM_IS_EMPTY(elem);
725
const apr_xml_attr *attr;
727
if (elem->ns == APR_XML_NS_NONE) {
728
len = sprintf(s, "<%s", elem->name);
731
ns = ns_map ? ns_map[elem->ns] : elem->ns;
732
len = sprintf(s, "<ns%d:%s", ns, elem->name);
736
for (attr = elem->attr; attr; attr = attr->next) {
737
if (attr->ns == APR_XML_NS_NONE)
738
len = sprintf(s, " %s=\"%s\"", attr->name, attr->value);
740
len = sprintf(s, " ns%d:%s=\"%s\"", attr->ns, attr->name, attr->value);
744
/* add the xml:lang value if necessary */
745
if (elem->lang != NULL &&
746
(style == APR_XML_X2T_FULL_NS_LANG ||
747
elem->parent == NULL ||
748
elem->lang != elem->parent->lang)) {
749
len = sprintf(s, " xml:lang=\"%s\"", elem->lang);
753
/* add namespace definitions, if required */
754
if (style == APR_XML_X2T_FULL_NS_LANG) {
757
for (i = namespaces->nelts; i--;) {
758
len = sprintf(s, " xmlns:ns%d=\"%s\"", i,
759
APR_XML_GET_URI_ITEM(namespaces, i));
764
/* no more to do. close it up and go. */
774
else if (style == APR_XML_X2T_LANG_INNER) {
775
/* prepend the xml:lang value */
776
if (elem->lang != NULL) {
777
len = strlen(elem->lang);
778
memcpy(s, elem->lang, len);
784
s = write_text(s, elem->first_cdata.first);
786
for (child = elem->first_child; child; child = child->next) {
787
s = write_elem(s, child, APR_XML_X2T_FULL, NULL, ns_map);
788
s = write_text(s, child->following_cdata.first);
791
if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
792
if (elem->ns == APR_XML_NS_NONE) {
793
len = sprintf(s, "</%s>", elem->name);
796
ns = ns_map ? ns_map[elem->ns] : elem->ns;
797
len = sprintf(s, "</ns%d:%s>", ns, elem->name);
805
APU_DECLARE(void) apr_xml_quote_elem(apr_pool_t *p, apr_xml_elem *elem)
808
apr_xml_attr *scan_attr;
809
apr_xml_elem *scan_elem;
811
/* convert the element's text */
812
for (scan_txt = elem->first_cdata.first;
814
scan_txt = scan_txt->next) {
815
scan_txt->text = apr_xml_quote_string(p, scan_txt->text, 0);
817
for (scan_txt = elem->following_cdata.first;
819
scan_txt = scan_txt->next) {
820
scan_txt->text = apr_xml_quote_string(p, scan_txt->text, 0);
823
/* convert the attribute values */
824
for (scan_attr = elem->attr;
826
scan_attr = scan_attr->next) {
827
scan_attr->value = apr_xml_quote_string(p, scan_attr->value, 1);
830
/* convert the child elements */
831
for (scan_elem = elem->first_child;
833
scan_elem = scan_elem->next) {
834
apr_xml_quote_elem(p, scan_elem);
838
/* convert an element to a text string */
839
APU_DECLARE(void) apr_xml_to_text(apr_pool_t * p, const apr_xml_elem *elem,
840
int style, apr_array_header_t *namespaces,
841
int *ns_map, const char **pbuf,
844
/* get the exact size, plus a null terminator */
845
apr_size_t size = elem_size(elem, style, namespaces, ns_map) + 1;
846
char *s = apr_palloc(p, size);
848
(void) write_elem(s, elem, style, namespaces, ns_map);
856
APU_DECLARE(const char *) apr_xml_empty_elem(apr_pool_t * p,
857
const apr_xml_elem *elem)
859
if (elem->ns == APR_XML_NS_NONE) {
861
* The prefix (xml...) is already within the prop name, or
862
* the element simply has no prefix.
864
return apr_psprintf(p, "<%s/>" DEBUG_CR, elem->name);
867
return apr_psprintf(p, "<ns%d:%s/>" DEBUG_CR, elem->ns, elem->name);
870
/* return the URI's (existing) index, or insert it and return a new index */
871
APU_DECLARE(int) apr_xml_insert_uri(apr_array_header_t *uri_array,
877
/* never insert an empty URI; this index is always APR_XML_NS_NONE */
879
return APR_XML_NS_NONE;
881
for (i = uri_array->nelts; i--;) {
882
if (strcmp(uri, APR_XML_GET_URI_ITEM(uri_array, i)) == 0)
886
pelt = apr_array_push(uri_array);
887
*pelt = uri; /* assume uri is const or in a pool */
888
return uri_array->nelts - 1;
891
/* convert the element to EBCDIC */
892
#if APR_CHARSET_EBCDIC
893
static apr_status_t apr_xml_parser_convert_elem(apr_xml_elem *e,
894
apr_xlate_t *convset)
899
apr_size_t inbytes_left, outbytes_left;
902
inbytes_left = outbytes_left = strlen(e->name);
903
status = apr_xlate_conv_buffer(convset, e->name, &inbytes_left, (char *) e->name, &outbytes_left);
908
for (t = e->first_cdata.first; t != NULL; t = t->next) {
909
inbytes_left = outbytes_left = strlen(t->text);
910
status = apr_xlate_conv_buffer(convset, t->text, &inbytes_left, (char *) t->text, &outbytes_left);
916
for (t = e->following_cdata.first; t != NULL; t = t->next) {
917
inbytes_left = outbytes_left = strlen(t->text);
918
status = apr_xlate_conv_buffer(convset, t->text, &inbytes_left, (char *) t->text, &outbytes_left);
924
for (a = e->attr; a != NULL; a = a->next) {
925
inbytes_left = outbytes_left = strlen(a->name);
926
status = apr_xlate_conv_buffer(convset, a->name, &inbytes_left, (char *) a->name, &outbytes_left);
930
inbytes_left = outbytes_left = strlen(a->value);
931
status = apr_xlate_conv_buffer(convset, a->value, &inbytes_left, (char *) a->value, &outbytes_left);
937
for (ec = e->first_child; ec != NULL; ec = ec->next) {
938
status = apr_xml_parser_convert_elem(ec, convset);
946
/* convert the whole document to EBCDIC */
947
APU_DECLARE(apr_status_t) apr_xml_parser_convert_doc(apr_pool_t *pool,
949
apr_xlate_t *convset)
952
/* Don't convert the namespaces: they are constant! */
953
if (pdoc->namespaces != NULL) {
955
apr_array_header_t *namespaces;
956
namespaces = apr_array_make(pool, pdoc->namespaces->nelts, sizeof(const char *));
957
if (namespaces == NULL)
959
for (i = 0; i < pdoc->namespaces->nelts; i++) {
960
apr_size_t inbytes_left, outbytes_left;
961
char *ptr = (char *) APR_XML_GET_URI_ITEM(pdoc->namespaces, i);
962
ptr = apr_pstrdup(pool, ptr);
965
inbytes_left = outbytes_left = strlen(ptr);
966
status = apr_xlate_conv_buffer(convset, ptr, &inbytes_left, ptr, &outbytes_left);
970
apr_xml_insert_uri(namespaces, ptr);
972
pdoc->namespaces = namespaces;
974
return apr_xml_parser_convert_elem(pdoc->root, convset);