Annotation of XML/tree.c, revision 1.33

1.1       veillard    1: /*
                      2:  * tree.c : implemetation of access function for an XML tree.
1.11      veillard    3:  *
                      4:  * See Copyright for the status of this software.
                      5:  *
1.32      daniel      6:  * TODO Cleanup the Dump mechanism.
1.17      daniel      7:  *
1.32      daniel      8:  * Daniel.Veillard@w3.org
1.1       veillard    9:  */
                     10: 
1.23      daniel     11: #include "config.h"
1.1       veillard   12: #include <stdio.h>
                     13: #include <ctype.h>
1.23      daniel     14: #include <stdlib.h>
1.7       veillard   15: #include <string.h> /* for memset() only ! */
1.1       veillard   16: 
1.23      daniel     17: #ifdef HAVE_ZLIB_H
                     18: #include <zlib.h>
                     19: #endif
                     20: 
1.1       veillard   21: #include "tree.h"
1.6       veillard   22: #include "entities.h"
1.33    ! daniel     23: #include "valid.h"
1.1       veillard   24: 
1.7       veillard   25: static CHAR xmlStringText[] = { 't', 'e', 'x', 't', 0 };
1.12      daniel     26: int oldXMLWDcompatibility = 0;
1.21      daniel     27: int xmlIndentTreeOutput = 1;
1.7       veillard   28: 
1.23      daniel     29: static int xmlCompressMode = 0;
                     30: 
1.32      daniel     31: #define UPDATE_LAST_CHILD(n) if ((n) != NULL) {                                \
                     32:     xmlNodePtr ulccur = (n)->childs;                                   \
                     33:     if (ulccur == NULL) {                                              \
                     34:         (n)->last = NULL;                                              \
                     35:     } else {                                                           \
                     36:         while (ulccur->next != NULL) ulccur = ulccur->next;            \
                     37:        (n)->last = ulccur;                                             \
                     38: }   }
                     39: 
1.1       veillard   40: /************************************************************************
                     41:  *                                                                     *
                     42:  *             Allocation and deallocation of basic structures         *
                     43:  *                                                                     *
                     44:  ************************************************************************/
                     45:  
1.23      daniel     46: /**
                     47:  * xmlUpgradeOldNs:
                     48:  * @doc:  a document pointer
                     49:  * 
                     50:  * Upgrade old style Namespaces (PI) and move them to the root of the document.
1.19      daniel     51:  */
1.28      daniel     52: void
                     53: xmlUpgradeOldNs(xmlDocPtr doc) {
1.19      daniel     54:     xmlNsPtr cur;
                     55: 
                     56:     if ((doc == NULL) || (doc->oldNs == NULL)) return;
                     57:     if (doc->root == NULL) {
                     58:         fprintf(stderr, "xmlUpgradeOldNs: failed no root !\n");
                     59:        return;
                     60:     }
                     61: 
                     62:     cur = doc->oldNs;
                     63:     while (cur->next != NULL) {
                     64:        cur->type = XML_LOCAL_NAMESPACE;
                     65:         cur = cur->next;
                     66:     }
                     67:     cur->type = XML_LOCAL_NAMESPACE;
                     68:     cur->next = doc->root->nsDef;
                     69:     doc->root->nsDef = doc->oldNs;
                     70:     doc->oldNs = NULL;
                     71: }
                     72: 
1.23      daniel     73: /**
                     74:  * xmlNewNs:
                     75:  * @node:  the element carrying the namespace
                     76:  * @href:  the URI associated
                     77:  * @prefix:  the prefix for the namespace
                     78:  *
1.17      daniel     79:  * Creation of a new Namespace.
1.23      daniel     80:  * return values: returns a new namespace pointer
1.1       veillard   81:  */
1.28      daniel     82: xmlNsPtr
                     83: xmlNewNs(xmlNodePtr node, const CHAR *href, const CHAR *prefix) {
1.16      daniel     84:     xmlNsPtr cur;
1.1       veillard   85: 
1.19      daniel     86:     if (href == NULL) {
                     87:         fprintf(stderr, "xmlNewNs: href == NULL !\n");
                     88:        return(NULL);
                     89:     }
                     90: 
1.1       veillard   91:     /*
                     92:      * Allocate a new DTD and fill the fields.
                     93:      */
1.16      daniel     94:     cur = (xmlNsPtr) malloc(sizeof(xmlNs));
1.1       veillard   95:     if (cur == NULL) {
1.16      daniel     96:         fprintf(stderr, "xmlNewNs : malloc failed\n");
1.1       veillard   97:        return(NULL);
                     98:     }
                     99: 
1.19      daniel    100:     cur->type = XML_LOCAL_NAMESPACE;
                    101:     if (href != NULL)
                    102:        cur->href = xmlStrdup(href); 
                    103:     else
                    104:         cur->href = NULL;
                    105:     if (prefix != NULL)
                    106:        cur->prefix = xmlStrdup(prefix); 
                    107:     else
                    108:         cur->prefix = NULL;
                    109: 
                    110:     /*
                    111:      * Add it at the end to preserve parsing order ...
                    112:      */
1.1       veillard  113:     cur->next = NULL;
1.19      daniel    114:     if (node != NULL) {
                    115:        if (node->nsDef == NULL) {
                    116:            node->nsDef = cur;
                    117:        } else {
                    118:            xmlNsPtr prev = node->nsDef;
                    119: 
                    120:            while (prev->next != NULL) prev = prev->next;
                    121:            prev->next = cur;
                    122:        }
                    123:     }
                    124: 
                    125:     return(cur);
                    126: }
                    127: 
1.23      daniel    128: /**
                    129:  * xmlNewGlobalNs:
                    130:  * @doc:  the document carrying the namespace
                    131:  * @href:  the URI associated
                    132:  * @prefix:  the prefix for the namespace
                    133:  *
                    134:  * Creation of a Namespace, the old way using PI and without scoping, to AVOID.
                    135:  * return values: returns a new namespace pointer
1.19      daniel    136:  */
1.28      daniel    137: xmlNsPtr
                    138: xmlNewGlobalNs(xmlDocPtr doc, const CHAR *href, const CHAR *prefix) {
1.19      daniel    139:     xmlNsPtr cur;
                    140: 
                    141:     /*
                    142:      * Allocate a new DTD and fill the fields.
                    143:      */
                    144:     cur = (xmlNsPtr) malloc(sizeof(xmlNs));
                    145:     if (cur == NULL) {
1.31      daniel    146:         fprintf(stderr, "xmlNewGlobalNs : malloc failed\n");
1.19      daniel    147:        return(NULL);
                    148:     }
                    149: 
                    150:     cur->type = XML_GLOBAL_NAMESPACE;
1.1       veillard  151:     if (href != NULL)
1.7       veillard  152:        cur->href = xmlStrdup(href); 
1.1       veillard  153:     else
                    154:         cur->href = NULL;
1.16      daniel    155:     if (prefix != NULL)
                    156:        cur->prefix = xmlStrdup(prefix); 
1.1       veillard  157:     else
1.16      daniel    158:         cur->prefix = NULL;
1.17      daniel    159: 
                    160:     /*
                    161:      * Add it at the end to preserve parsing order ...
                    162:      */
                    163:     cur->next = NULL;
1.1       veillard  164:     if (doc != NULL) {
1.19      daniel    165:        if (doc->oldNs == NULL) {
                    166:            doc->oldNs = cur;
1.17      daniel    167:        } else {
1.19      daniel    168:            xmlNsPtr prev = doc->oldNs;
1.17      daniel    169: 
                    170:            while (prev->next != NULL) prev = prev->next;
                    171:            prev->next = cur;
                    172:        }
1.1       veillard  173:     }
1.3       veillard  174: 
1.1       veillard  175:     return(cur);
                    176: }
                    177: 
1.23      daniel    178: /**
                    179:  * xmlSetNs:
                    180:  * @node:  a node in the document
                    181:  * @ns:  a namespace pointer
                    182:  *
                    183:  * Associate a namespace to a node, a posteriori.
1.19      daniel    184:  */
1.28      daniel    185: void
                    186: xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
1.19      daniel    187:     if (node == NULL) {
                    188:         fprintf(stderr, "xmlSetNs: node == NULL\n");
                    189:        return;
                    190:     }
                    191:     node->ns = ns;
                    192: }
                    193: 
1.23      daniel    194: /**
                    195:  * xmlFreeNs:
                    196:  * @cur:  the namespace pointer
                    197:  *
                    198:  * Free up the structures associated to a namespace
1.1       veillard  199:  */
1.28      daniel    200: void
                    201: xmlFreeNs(xmlNsPtr cur) {
1.1       veillard  202:     if (cur == NULL) {
1.17      daniel    203:         fprintf(stderr, "xmlFreeNs : ns == NULL\n");
1.1       veillard  204:        return;
                    205:     }
                    206:     if (cur->href != NULL) free((char *) cur->href);
1.16      daniel    207:     if (cur->prefix != NULL) free((char *) cur->prefix);
                    208:     memset(cur, -1, sizeof(xmlNs));
1.1       veillard  209:     free(cur);
                    210: }
                    211: 
1.23      daniel    212: /**
                    213:  * xmlFreeNsList:
                    214:  * @cur:  the first namespace pointer
                    215:  *
                    216:  * Free up all the structures associated to the chained namespaces.
1.6       veillard  217:  */
1.28      daniel    218: void
                    219: xmlFreeNsList(xmlNsPtr cur) {
1.16      daniel    220:     xmlNsPtr next;
1.6       veillard  221:     if (cur == NULL) {
1.16      daniel    222:         fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
1.6       veillard  223:        return;
                    224:     }
                    225:     while (cur != NULL) {
                    226:         next = cur->next;
1.16      daniel    227:         xmlFreeNs(cur);
1.6       veillard  228:        cur = next;
                    229:     }
                    230: }
                    231: 
1.23      daniel    232: /**
                    233:  * xmlNewDtd:
                    234:  * @doc:  the document pointer
                    235:  * @name:  the DTD name
                    236:  * @ExternalID:  the external ID
                    237:  * @SystemID:  the system ID
                    238:  *
1.17      daniel    239:  * Creation of a new DTD.
1.23      daniel    240:  * return values: a pointer to the new DTD structure
1.17      daniel    241:  */
1.28      daniel    242: xmlDtdPtr
                    243: xmlNewDtd(xmlDocPtr doc, const CHAR *name,
1.17      daniel    244:                     const CHAR *ExternalID, const CHAR *SystemID) {
                    245:     xmlDtdPtr cur;
                    246: 
1.31      daniel    247:     if ((doc != NULL) && (doc->extSubset != NULL)) {
1.17      daniel    248:         fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
1.31      daniel    249:            /* !!! */ (char *) name, doc->name,
                    250:            /* !!! */ (char *)doc->extSubset->name);
1.17      daniel    251:     }
                    252: 
                    253:     /*
                    254:      * Allocate a new DTD and fill the fields.
                    255:      */
                    256:     cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
                    257:     if (cur == NULL) {
1.31      daniel    258:         fprintf(stderr, "xmlNewDtd : malloc failed\n");
                    259:        return(NULL);
                    260:     }
                    261: 
                    262:     if (name != NULL)
                    263:        cur->name = xmlStrdup(name); 
                    264:     else
                    265:         cur->name = NULL;
                    266:     if (ExternalID != NULL)
                    267:        cur->ExternalID = xmlStrdup(ExternalID); 
                    268:     else
                    269:         cur->ExternalID = NULL;
                    270:     if (SystemID != NULL)
                    271:        cur->SystemID = xmlStrdup(SystemID); 
                    272:     else
                    273:         cur->SystemID = NULL;
                    274:     cur->elements = NULL;
                    275:     cur->entities = NULL;
                    276:     if (doc != NULL)
                    277:        doc->extSubset = cur;
                    278: 
                    279:     return(cur);
                    280: }
                    281: 
                    282: /**
                    283:  * xmlCreateIntSubset:
                    284:  * @doc:  the document pointer
                    285:  * @name:  the DTD name
                    286:  * @ExternalID:  the external ID
                    287:  * @SystemID:  the system ID
                    288:  *
                    289:  * Creatte the internal subset of a document
                    290:  * return values: a pointer to the new DTD structure
                    291:  */
                    292: xmlDtdPtr
                    293: xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
                    294:                    const CHAR *ExternalID, const CHAR *SystemID) {
                    295:     xmlDtdPtr cur;
                    296: 
                    297:     if ((doc != NULL) && (doc->intSubset != NULL)) {
                    298:         fprintf(stderr, 
                    299:      "xmlCreateIntSubset(): document %s already have an internal subset\n",
                    300:            doc->name);
                    301:        return(NULL);
                    302:     }
                    303: 
                    304:     /*
                    305:      * Allocate a new DTD and fill the fields.
                    306:      */
                    307:     cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
                    308:     if (cur == NULL) {
                    309:         fprintf(stderr, "xmlNewDtd : malloc failed\n");
1.17      daniel    310:        return(NULL);
                    311:     }
                    312: 
                    313:     if (name != NULL)
                    314:        cur->name = xmlStrdup(name); 
                    315:     else
                    316:         cur->name = NULL;
                    317:     if (ExternalID != NULL)
                    318:        cur->ExternalID = xmlStrdup(ExternalID); 
                    319:     else
                    320:         cur->ExternalID = NULL;
                    321:     if (SystemID != NULL)
                    322:        cur->SystemID = xmlStrdup(SystemID); 
                    323:     else
                    324:         cur->SystemID = NULL;
                    325:     cur->elements = NULL;
                    326:     cur->entities = NULL;
1.31      daniel    327:     if (doc != NULL)
                    328:        doc->intSubset = cur;
1.17      daniel    329: 
                    330:     return(cur);
                    331: }
                    332: 
1.23      daniel    333: /**
                    334:  * xmlFreeDtd:
                    335:  * @cur:  the DTD structure to free up
                    336:  *
                    337:  * Free a DTD structure.
1.17      daniel    338:  */
1.28      daniel    339: void
                    340: xmlFreeDtd(xmlDtdPtr cur) {
1.17      daniel    341:     if (cur == NULL) {
                    342:         fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
                    343:        return;
                    344:     }
                    345:     if (cur->name != NULL) free((char *) cur->name);
                    346:     if (cur->SystemID != NULL) free((char *) cur->SystemID);
                    347:     if (cur->ExternalID != NULL) free((char *) cur->ExternalID);
                    348:     if (cur->elements != NULL)
1.33    ! daniel    349:         xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1.17      daniel    350:     if (cur->entities != NULL)
                    351:         xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
                    352:     memset(cur, -1, sizeof(xmlDtd));
                    353:     free(cur);
                    354: }
                    355: 
1.23      daniel    356: /**
                    357:  * xmlNewDoc:
                    358:  * @version:  CHAR string giving the version of XML "1.0"
                    359:  *
                    360:  * Create a new document
1.1       veillard  361:  */
1.28      daniel    362: xmlDocPtr
                    363: xmlNewDoc(const CHAR *version) {
1.1       veillard  364:     xmlDocPtr cur;
                    365: 
                    366:     if (version == NULL) {
                    367:         fprintf(stderr, "xmlNewDoc : version == NULL\n");
                    368:        return(NULL);
                    369:     }
                    370: 
                    371:     /*
                    372:      * Allocate a new document and fill the fields.
                    373:      */
                    374:     cur = (xmlDocPtr) malloc(sizeof(xmlDoc));
                    375:     if (cur == NULL) {
                    376:         fprintf(stderr, "xmlNewDoc : malloc failed\n");
                    377:        return(NULL);
                    378:     }
                    379: 
1.23      daniel    380:     cur->type = XML_DOCUMENT_NODE;
1.7       veillard  381:     cur->version = xmlStrdup(version); 
1.18      daniel    382:     cur->name = NULL;
1.1       veillard  383:     cur->root = NULL; 
1.31      daniel    384:     cur->intSubset = NULL;
                    385:     cur->extSubset = NULL;
1.19      daniel    386:     cur->oldNs = NULL;
1.15      daniel    387:     cur->encoding = NULL;
                    388:     cur->standalone = -1;
1.23      daniel    389:     cur->compression = xmlCompressMode;
                    390: #ifndef WITHOUT_CORBA
                    391:     cur->_private = NULL;
                    392:     cur->vepv = NULL;
                    393: #endif
1.1       veillard  394:     return(cur);
                    395: }
                    396: 
1.23      daniel    397: /**
                    398:  * xmlFreeDoc:
                    399:  * @cur:  pointer to the document
                    400:  * @:  
                    401:  *
                    402:  * Free up all the structures used by a document, tree included.
1.1       veillard  403:  */
1.28      daniel    404: void
                    405: xmlFreeDoc(xmlDocPtr cur) {
1.1       veillard  406:     if (cur == NULL) {
1.31      daniel    407: #ifdef DEBUG_TREE
1.1       veillard  408:         fprintf(stderr, "xmlFreeDoc : document == NULL\n");
1.31      daniel    409: #endif
1.1       veillard  410:        return;
                    411:     }
                    412:     free((char *) cur->version);
1.17      daniel    413:     if (cur->name != NULL) free((char *) cur->name);
1.15      daniel    414:     if (cur->encoding != NULL) free((char *) cur->encoding);
1.1       veillard  415:     if (cur->root != NULL) xmlFreeNode(cur->root);
1.31      daniel    416:     if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
                    417:     if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
                    418:     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1.1       veillard  419:     memset(cur, -1, sizeof(xmlDoc));
                    420:     free(cur);
                    421: }
                    422: 
1.23      daniel    423: /**
1.28      daniel    424:  * xmlStringLenGetNodeList:
                    425:  * @doc:  the document
                    426:  * @value:  the value of the text
                    427:  * @int len:  the length of the string value
                    428:  *
                    429:  * Parse the value string and build the node list associated. Should
                    430:  * produce a flat tree with only TEXTs and ENTITY_REFs.
                    431:  * return values: a pointer to the first child
                    432:  */
                    433: xmlNodePtr
                    434: xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
                    435:     xmlNodePtr ret = NULL, last = NULL;
                    436:     xmlNodePtr node;
                    437:     CHAR *val;
                    438:     const CHAR *cur = value;
                    439:     const CHAR *q;
                    440:     xmlEntityPtr ent;
                    441: 
                    442:     if (value == NULL) return(NULL);
                    443: 
                    444:     q = cur;
                    445:     while ((*cur != 0) && (cur - value < len)) {
                    446:        if (*cur == '&') {
                    447:            /*
                    448:             * Save the current text.
                    449:             */
                    450:             if (cur != q) {
                    451:                if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
                    452:                    xmlNodeAddContentLen(last, q, cur - q);
                    453:                } else {
                    454:                    node = xmlNewDocTextLen(doc, q, cur - q);
                    455:                    if (node == NULL) return(ret);
                    456:                    if (last == NULL)
                    457:                        last = ret = node;
                    458:                    else {
                    459:                        last->next = node;
                    460:                        node->prev = last;
                    461:                        last = node;
                    462:                    }
                    463:                }
                    464:            }
                    465:            /*
                    466:             * Read the entity string
                    467:             */
                    468:            cur++;
                    469:            q = cur;
                    470:            while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
                    471:            if ((*cur == 0) || (cur - value >= len)) {
                    472:                fprintf(stderr,
                    473:                        "xmlStringGetNodeList: unterminated entity %30s\n", q);
                    474:                return(ret);
                    475:            }
                    476:             if (cur != q) {
                    477:                /*
                    478:                 * Predefined entities don't generate nodes
                    479:                 */
                    480:                val = xmlStrndup(q, cur - q);
                    481:                ent = xmlGetDocEntity(doc, val);
                    482:                if ((ent != NULL) &&
                    483:                    (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
                    484:                    if (last == NULL) {
                    485:                        node = xmlNewDocText(doc, ent->content);
                    486:                        last = ret = node;
                    487:                    } else
                    488:                        xmlNodeAddContent(last, ent->content);
                    489:                        
                    490:                } else {
                    491:                    /*
                    492:                     * Create a new REFERENCE_REF node
                    493:                     */
                    494:                    node = xmlNewReference(doc, val);
1.30      daniel    495:                    if (node == NULL) {
                    496:                        if (val != NULL) free(val);
                    497:                        return(ret);
                    498:                    }
1.28      daniel    499:                    if (last == NULL)
                    500:                        last = ret = node;
                    501:                    else {
                    502:                        last->next = node;
                    503:                        node->prev = last;
                    504:                        last = node;
                    505:                    }
                    506:                }
                    507:                free(val);
                    508:            }
                    509:            cur++;
                    510:            q = cur;
                    511:        } else 
                    512:            cur++;
                    513:     }
                    514:     if (cur != q) {
                    515:         /*
                    516:         * Handle the last piece of text.
                    517:         */
                    518:        if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
                    519:            xmlNodeAddContentLen(last, q, cur - q);
                    520:        } else {
                    521:            node = xmlNewDocTextLen(doc, q, cur - q);
                    522:            if (node == NULL) return(ret);
                    523:            if (last == NULL)
                    524:                last = ret = node;
                    525:            else {
                    526:                last->next = node;
                    527:                node->prev = last;
                    528:                last = node;
                    529:            }
                    530:        }
                    531:     }
                    532:     return(ret);
                    533: }
                    534: 
                    535: /**
1.24      daniel    536:  * xmlStringGetNodeList:
                    537:  * @doc:  the document
1.23      daniel    538:  * @value:  the value of the attribute
                    539:  *
1.24      daniel    540:  * Parse the value string and build the node list associated. Should
                    541:  * produce a flat tree with only TEXTs and ENTITY_REFs.
1.23      daniel    542:  * return values: a pointer to the first child
                    543:  */
1.28      daniel    544: xmlNodePtr
                    545: xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
1.23      daniel    546:     xmlNodePtr ret = NULL, last = NULL;
                    547:     xmlNodePtr node;
                    548:     CHAR *val;
                    549:     const CHAR *cur = value;
                    550:     const CHAR *q;
1.28      daniel    551:     xmlEntityPtr ent;
1.23      daniel    552: 
                    553:     if (value == NULL) return(NULL);
                    554: 
                    555:     q = cur;
                    556:     while (*cur != 0) {
                    557:        if (*cur == '&') {
1.28      daniel    558:            /*
                    559:             * Save the current text.
                    560:             */
1.23      daniel    561:             if (cur != q) {
1.28      daniel    562:                if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
                    563:                    xmlNodeAddContentLen(last, q, cur - q);
                    564:                } else {
                    565:                    node = xmlNewDocTextLen(doc, q, cur - q);
                    566:                    if (node == NULL) return(ret);
                    567:                    if (last == NULL)
                    568:                        last = ret = node;
                    569:                    else {
                    570:                        last->next = node;
                    571:                        node->prev = last;
                    572:                        last = node;
                    573:                    }
1.23      daniel    574:                }
                    575:            }
1.28      daniel    576:            /*
                    577:             * Read the entity string
                    578:             */
1.23      daniel    579:            cur++;
                    580:            q = cur;
                    581:            while ((*cur != 0) && (*cur != ';')) cur++;
                    582:            if (*cur == 0) {
1.24      daniel    583:                fprintf(stderr,
                    584:                        "xmlStringGetNodeList: unterminated entity %30s\n", q);
1.23      daniel    585:                return(ret);
                    586:            }
                    587:             if (cur != q) {
1.28      daniel    588:                /*
                    589:                 * Predefined entities don't generate nodes
                    590:                 */
1.23      daniel    591:                val = xmlStrndup(q, cur - q);
1.28      daniel    592:                ent = xmlGetDocEntity(doc, val);
                    593:                if ((ent != NULL) &&
                    594:                    (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
                    595:                    if (last == NULL) {
                    596:                        node = xmlNewDocText(doc, ent->content);
                    597:                        last = ret = node;
                    598:                    } else
                    599:                        xmlNodeAddContent(last, ent->content);
                    600:                        
                    601:                } else {
                    602:                    /*
                    603:                     * Create a new REFERENCE_REF node
                    604:                     */
                    605:                    node = xmlNewReference(doc, val);
1.30      daniel    606:                    if (node == NULL) {
                    607:                        if (val != NULL) free(val);
                    608:                        return(ret);
                    609:                    }
1.28      daniel    610:                    if (last == NULL)
                    611:                        last = ret = node;
                    612:                    else {
                    613:                        last->next = node;
                    614:                        node->prev = last;
                    615:                        last = node;
                    616:                    }
1.23      daniel    617:                }
                    618:                free(val);
                    619:            }
                    620:            cur++;
                    621:            q = cur;
                    622:        } else 
                    623:            cur++;
                    624:     }
                    625:     if (cur != q) {
1.28      daniel    626:         /*
                    627:         * Handle the last piece of text.
                    628:         */
                    629:        if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
                    630:            xmlNodeAddContentLen(last, q, cur - q);
                    631:        } else {
                    632:            node = xmlNewDocTextLen(doc, q, cur - q);
                    633:            if (node == NULL) return(ret);
                    634:            if (last == NULL)
                    635:                last = ret = node;
                    636:            else {
                    637:                last->next = node;
                    638:                node->prev = last;
                    639:                last = node;
                    640:            }
1.23      daniel    641:        }
                    642:     }
                    643:     return(ret);
                    644: }
                    645: 
                    646: /**
1.24      daniel    647:  * xmlNodeListGetString:
1.23      daniel    648:  * @doc:  the document
1.24      daniel    649:  * @list:  a Node list
1.23      daniel    650:  * @inLine:  should we replace entity contents or show their external form
                    651:  *
1.24      daniel    652:  * Returns the string equivalent to the text contained in the Node list
                    653:  * made of TEXTs and ENTITY_REFs
                    654:  * return values: a pointer to the string copy, the calller must free it.
1.23      daniel    655:  */
1.28      daniel    656: CHAR *
                    657: xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
1.24      daniel    658:     xmlNodePtr node = list;
1.23      daniel    659:     CHAR *ret = NULL;
                    660:     xmlEntityPtr ent;
                    661: 
1.24      daniel    662:     if (list == NULL) return(NULL);
1.23      daniel    663: 
                    664:     while (node != NULL) {
                    665:         if (node->type == XML_TEXT_NODE) {
                    666:            if (inLine)
                    667:                ret = xmlStrcat(ret, node->content);
                    668:            else
                    669:                ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
                    670:        } else if (node->type == XML_ENTITY_REF_NODE) {
                    671:            if (inLine) {
                    672:                ent = xmlGetDocEntity(doc, node->name);
                    673:                if (ent != NULL)
                    674:                    ret = xmlStrcat(ret, ent->content);
                    675:                else
                    676:                    ret = xmlStrcat(ret, node->content);
                    677:             } else {
                    678:                CHAR buf[2];
                    679:                buf[0] = '&'; buf[1] = 0;
                    680:                ret = xmlStrncat(ret, buf, 1);
                    681:                ret = xmlStrcat(ret, node->name);
                    682:                buf[0] = ';'; buf[1] = 0;
                    683:                ret = xmlStrncat(ret, buf, 1);
                    684:            }
1.24      daniel    685:        }
                    686: #if 0
                    687:        else {
                    688:            fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
1.23      daniel    689:                    node->type);
                    690:        }
1.24      daniel    691: #endif
1.23      daniel    692:        node = node->next;
                    693:     }
                    694:     return(ret);
                    695: }
                    696: 
                    697: /**
                    698:  * xmlNewProp:
                    699:  * @node:  the holding node
                    700:  * @name:  the name of the attribute
                    701:  * @value:  the value of the attribute
                    702:  *
                    703:  * Create a new property carried by a node.
                    704:  * return values: a pointer to the attribute
1.1       veillard  705:  */
1.28      daniel    706: xmlAttrPtr
                    707: xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
1.20      daniel    708:     xmlAttrPtr cur;
1.1       veillard  709: 
                    710:     if (name == NULL) {
                    711:         fprintf(stderr, "xmlNewProp : name == NULL\n");
                    712:        return(NULL);
                    713:     }
                    714: 
                    715:     /*
                    716:      * Allocate a new property and fill the fields.
                    717:      */
1.20      daniel    718:     cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
1.1       veillard  719:     if (cur == NULL) {
                    720:         fprintf(stderr, "xmlNewProp : malloc failed\n");
                    721:        return(NULL);
                    722:     }
                    723: 
1.23      daniel    724:     cur->type = XML_ATTRIBUTE_NODE;
1.1       veillard  725:     cur->node = node; 
1.7       veillard  726:     cur->name = xmlStrdup(name);
1.1       veillard  727:     if (value != NULL)
1.24      daniel    728:        cur->val = xmlStringGetNodeList(node->doc, value);
1.1       veillard  729:     else 
1.23      daniel    730:        cur->val = NULL;
                    731: #ifndef WITHOUT_CORBA
                    732:     cur->_private = NULL;
                    733:     cur->vepv = NULL;
                    734: #endif
1.17      daniel    735: 
                    736:     /*
                    737:      * Add it at the end to preserve parsing order ...
                    738:      */
                    739:     cur->next = NULL;
1.1       veillard  740:     if (node != NULL) {
1.17      daniel    741:        if (node->properties == NULL) {
                    742:            node->properties = cur;
                    743:        } else {
1.20      daniel    744:            xmlAttrPtr prev = node->properties;
1.17      daniel    745: 
                    746:            while (prev->next != NULL) prev = prev->next;
                    747:            prev->next = cur;
                    748:        }
                    749:     }
1.1       veillard  750:     return(cur);
                    751: }
                    752: 
1.23      daniel    753: /**
                    754:  * xmlNewDocProp:
                    755:  * @doc:  the document
                    756:  * @name:  the name of the attribute
                    757:  * @value:  the value of the attribute
                    758:  *
                    759:  * Create a new property carried by a document.
                    760:  * return values: a pointer to the attribute
                    761:  */
1.28      daniel    762: xmlAttrPtr
                    763: xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
1.23      daniel    764:     xmlAttrPtr cur;
                    765: 
                    766:     if (name == NULL) {
                    767:         fprintf(stderr, "xmlNewProp : name == NULL\n");
                    768:        return(NULL);
                    769:     }
                    770: 
                    771:     /*
                    772:      * Allocate a new property and fill the fields.
                    773:      */
                    774:     cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
                    775:     if (cur == NULL) {
                    776:         fprintf(stderr, "xmlNewProp : malloc failed\n");
                    777:        return(NULL);
                    778:     }
                    779: 
                    780:     cur->type = XML_ATTRIBUTE_NODE;
                    781:     cur->node = NULL; 
                    782:     cur->name = xmlStrdup(name);
                    783:     if (value != NULL)
1.24      daniel    784:        cur->val = xmlStringGetNodeList(doc, value);
1.23      daniel    785:     else 
                    786:        cur->val = NULL;
                    787: #ifndef WITHOUT_CORBA
                    788:     cur->_private = NULL;
                    789:     cur->vepv = NULL;
                    790: #endif
                    791: 
                    792:     cur->next = NULL;
                    793:     return(cur);
                    794: }
                    795: 
                    796: /**
                    797:  * xmlFreePropList:
                    798:  * @cur:  the first property in the list
                    799:  *
                    800:  * Free a property and all its siblings, all the childs are freed too.
1.1       veillard  801:  */
1.28      daniel    802: void
                    803: xmlFreePropList(xmlAttrPtr cur) {
1.20      daniel    804:     xmlAttrPtr next;
1.1       veillard  805:     if (cur == NULL) {
                    806:         fprintf(stderr, "xmlFreePropList : property == NULL\n");
                    807:        return;
                    808:     }
                    809:     while (cur != NULL) {
                    810:         next = cur->next;
                    811:         xmlFreeProp(cur);
                    812:        cur = next;
                    813:     }
                    814: }
                    815: 
1.23      daniel    816: /**
                    817:  * xmlFreeProp:
                    818:  * @cur:  the first property in the list
                    819:  *
                    820:  * Free one property, all the childs are freed too.
1.1       veillard  821:  */
1.28      daniel    822: void
                    823: xmlFreeProp(xmlAttrPtr cur) {
1.1       veillard  824:     if (cur == NULL) {
                    825:         fprintf(stderr, "xmlFreeProp : property == NULL\n");
                    826:        return;
                    827:     }
                    828:     if (cur->name != NULL) free((char *) cur->name);
1.23      daniel    829:     if (cur->val != NULL) xmlFreeNodeList(cur->val);
1.20      daniel    830:     memset(cur, -1, sizeof(xmlAttr));
1.1       veillard  831:     free(cur);
                    832: }
                    833: 
1.23      daniel    834: /**
                    835:  * xmlNewNode:
                    836:  * @ns:  namespace if any
                    837:  * @name:  the node name
                    838:  * @content:  the text content if any
                    839:  *
                    840:  * Creation of a new node element. @ns and @content are optionnal (NULL).
1.24      daniel    841:  * If content is non NULL, a child list containing the TEXTs and
                    842:  * ENTITY_REFs node will be created.
1.23      daniel    843:  * return values: a pointer to the new node object.
1.1       veillard  844:  */
1.28      daniel    845: xmlNodePtr
                    846: xmlNewNode(xmlNsPtr ns, const CHAR *name) {
1.1       veillard  847:     xmlNodePtr cur;
                    848: 
                    849:     if (name == NULL) {
                    850:         fprintf(stderr, "xmlNewNode : name == NULL\n");
                    851:        return(NULL);
                    852:     }
                    853: 
                    854:     /*
                    855:      * Allocate a new node and fill the fields.
                    856:      */
                    857:     cur = (xmlNodePtr) malloc(sizeof(xmlNode));
                    858:     if (cur == NULL) {
                    859:         fprintf(stderr, "xmlNewNode : malloc failed\n");
                    860:        return(NULL);
                    861:     }
                    862: 
1.23      daniel    863:     cur->type = XML_ELEMENT_NODE;
                    864:     cur->doc = NULL;
1.1       veillard  865:     cur->parent = NULL; 
1.23      daniel    866:     cur->next = NULL;
                    867:     cur->prev = NULL;
                    868:     cur->childs = NULL;
1.32      daniel    869:     cur->last = NULL;
1.23      daniel    870:     cur->properties = NULL;
1.22      daniel    871:     cur->name = xmlStrdup(name);
1.16      daniel    872:     cur->ns = ns;
1.19      daniel    873:     cur->nsDef = NULL;
1.24      daniel    874:     cur->content = NULL;
1.23      daniel    875: #ifndef WITHOUT_CORBA
                    876:     cur->_private = NULL;
                    877:     cur->vepv = NULL;
                    878: #endif
1.1       veillard  879:     return(cur);
                    880: }
                    881: 
1.23      daniel    882: /**
                    883:  * xmlNewDocNode:
                    884:  * @doc:  the document
                    885:  * @ns:  namespace if any
                    886:  * @name:  the node name
                    887:  * @content:  the text content if any
                    888:  *
                    889:  * Creation of a new node element within a document. @ns and @content
                    890:  * are optionnal (NULL).
                    891:  * return values: a pointer to the new node object.
                    892:  */
1.28      daniel    893: xmlNodePtr
                    894: xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1.23      daniel    895:                          const CHAR *name, CHAR *content) {
                    896:     xmlNodePtr cur;
                    897: 
1.24      daniel    898:     cur = xmlNewNode(ns, name);
                    899:     if (cur != NULL) {
                    900:         cur->doc = doc;
1.32      daniel    901:        if (content != NULL) {
1.24      daniel    902:            cur->childs = xmlStringGetNodeList(doc, content);
1.32      daniel    903:            UPDATE_LAST_CHILD(cur);
                    904:        }
1.24      daniel    905:     }
1.23      daniel    906:     return(cur);
                    907: }
                    908: 
                    909: 
                    910: /**
                    911:  * xmlNewText:
                    912:  * @content:  the text content
                    913:  *
                    914:  * Creation of a new text node.
                    915:  * return values: a pointer to the new node object.
1.3       veillard  916:  */
1.28      daniel    917: xmlNodePtr
                    918: xmlNewText(const CHAR *content) {
1.3       veillard  919:     xmlNodePtr cur;
                    920: 
                    921:     /*
                    922:      * Allocate a new node and fill the fields.
                    923:      */
                    924:     cur = (xmlNodePtr) malloc(sizeof(xmlNode));
                    925:     if (cur == NULL) {
1.19      daniel    926:         fprintf(stderr, "xmlNewText : malloc failed\n");
1.3       veillard  927:        return(NULL);
                    928:     }
                    929: 
1.23      daniel    930:     cur->type = XML_TEXT_NODE;
                    931:     cur->doc = NULL;
1.3       veillard  932:     cur->parent = NULL; 
                    933:     cur->next = NULL; 
1.23      daniel    934:     cur->prev = NULL; 
1.3       veillard  935:     cur->childs = NULL; 
1.32      daniel    936:     cur->last = NULL; 
1.3       veillard  937:     cur->properties = NULL; 
1.23      daniel    938:     cur->type = XML_TEXT_NODE;
1.18      daniel    939:     cur->name = xmlStrdup(xmlStringText);
1.16      daniel    940:     cur->ns = NULL;
1.19      daniel    941:     cur->nsDef = NULL;
1.3       veillard  942:     if (content != NULL)
1.7       veillard  943:        cur->content = xmlStrdup(content);
1.3       veillard  944:     else 
                    945:        cur->content = NULL;
                    946:     return(cur);
                    947: }
                    948: 
1.23      daniel    949: /**
                    950:  * xmlNewReference:
                    951:  * @doc: the document
                    952:  * @name:  the reference name, or the reference string with & and ;
                    953:  *
                    954:  * Creation of a new reference node.
                    955:  * return values: a pointer to the new node object.
                    956:  */
1.28      daniel    957: xmlNodePtr
                    958: xmlNewReference(xmlDocPtr doc, const CHAR *name) {
1.23      daniel    959:     xmlNodePtr cur;
                    960:     xmlEntityPtr ent;
                    961: 
                    962:     /*
                    963:      * Allocate a new node and fill the fields.
                    964:      */
                    965:     cur = (xmlNodePtr) malloc(sizeof(xmlNode));
                    966:     if (cur == NULL) {
                    967:         fprintf(stderr, "xmlNewText : malloc failed\n");
                    968:        return(NULL);
                    969:     }
                    970: 
                    971:     cur->type = XML_ENTITY_REF_NODE;
1.28      daniel    972:     cur->doc = doc;
1.23      daniel    973:     cur->parent = NULL; 
                    974:     cur->next = NULL; 
                    975:     cur->prev = NULL; 
                    976:     cur->childs = NULL; 
1.32      daniel    977:     cur->last = NULL; 
1.23      daniel    978:     cur->properties = NULL; 
                    979:     if (name[0] == '&') {
                    980:         int len;
                    981:         name++;
                    982:        len = xmlStrlen(name);
                    983:        if (name[len - 1] == ';')
                    984:            cur->name = xmlStrndup(name, len - 1);
                    985:        else
                    986:            cur->name = xmlStrndup(name, len);
                    987:     } else
                    988:        cur->name = xmlStrdup(name);
                    989:     cur->ns = NULL;
                    990:     cur->nsDef = NULL;
                    991: 
                    992:     ent = xmlGetDocEntity(doc, cur->name);
                    993:     if (ent != NULL)
                    994:        cur->content = ent->content;
                    995:     else
                    996:         cur->content = NULL;
                    997:     return(cur);
                    998: }
                    999: 
                   1000: /**
                   1001:  * xmlNewDocText:
                   1002:  * @doc: the document
                   1003:  * @content:  the text content
                   1004:  *
                   1005:  * Creation of a new text node within a document.
                   1006:  * return values: a pointer to the new node object.
                   1007:  */
1.28      daniel   1008: xmlNodePtr
                   1009: xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
1.23      daniel   1010:     xmlNodePtr cur;
                   1011: 
                   1012:     cur = xmlNewText(content);
                   1013:     if (cur != NULL) cur->doc = doc;
                   1014:     return(cur);
                   1015: }
                   1016: 
                   1017: /**
                   1018:  * xmlNewTextLen:
                   1019:  * @content:  the text content
                   1020:  * @len:  the text len.
                   1021:  *
                   1022:  * Creation of a new text node with an extra parameter for the content's lenght
                   1023:  * return values: a pointer to the new node object.
1.21      daniel   1024:  */
1.28      daniel   1025: xmlNodePtr
                   1026: xmlNewTextLen(const CHAR *content, int len) {
1.21      daniel   1027:     xmlNodePtr cur;
                   1028: 
                   1029:     /*
                   1030:      * Allocate a new node and fill the fields.
                   1031:      */
                   1032:     cur = (xmlNodePtr) malloc(sizeof(xmlNode));
                   1033:     if (cur == NULL) {
                   1034:         fprintf(stderr, "xmlNewText : malloc failed\n");
                   1035:        return(NULL);
                   1036:     }
                   1037: 
1.23      daniel   1038:     cur->type = XML_TEXT_NODE;
                   1039:     cur->doc = NULL; 
1.21      daniel   1040:     cur->parent = NULL; 
1.23      daniel   1041:     cur->prev = NULL; 
1.21      daniel   1042:     cur->next = NULL; 
                   1043:     cur->childs = NULL; 
1.32      daniel   1044:     cur->last = NULL; 
1.21      daniel   1045:     cur->properties = NULL; 
1.23      daniel   1046:     cur->type = XML_TEXT_NODE;
1.21      daniel   1047:     cur->name = xmlStrdup(xmlStringText);
                   1048:     cur->ns = NULL;
                   1049:     cur->nsDef = NULL;
                   1050:     if (content != NULL)
                   1051:        cur->content = xmlStrndup(content, len);
                   1052:     else 
                   1053:        cur->content = NULL;
                   1054:     return(cur);
                   1055: }
                   1056: 
1.23      daniel   1057: /**
                   1058:  * xmlNewDocTextLen:
                   1059:  * @doc: the document
                   1060:  * @content:  the text content
                   1061:  * @len:  the text len.
                   1062:  *
                   1063:  * Creation of a new text node with an extra content lenght parameter. The
                   1064:  * text node pertain to a given document.
                   1065:  * return values: a pointer to the new node object.
                   1066:  */
1.28      daniel   1067: xmlNodePtr
                   1068: xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
1.23      daniel   1069:     xmlNodePtr cur;
                   1070: 
                   1071:     cur = xmlNewTextLen(content, len);
                   1072:     if (cur != NULL) cur->doc = doc;
                   1073:     return(cur);
                   1074: }
                   1075: 
                   1076: /**
                   1077:  * xmlNewComment:
                   1078:  * @content:  the comment content
                   1079:  *
                   1080:  * Creation of a new node containing a comment.
                   1081:  * return values: a pointer to the new node object.
1.14      daniel   1082:  */
1.28      daniel   1083: xmlNodePtr
                   1084: xmlNewComment(CHAR *content) {
1.14      daniel   1085:     xmlNodePtr cur;
                   1086: 
                   1087:     /*
                   1088:      * Allocate a new node and fill the fields.
                   1089:      */
                   1090:     cur = (xmlNodePtr) malloc(sizeof(xmlNode));
                   1091:     if (cur == NULL) {
1.19      daniel   1092:         fprintf(stderr, "xmlNewComment : malloc failed\n");
1.14      daniel   1093:        return(NULL);
                   1094:     }
                   1095: 
1.23      daniel   1096:     cur->type = XML_COMMENT_NODE;
                   1097:     cur->doc = NULL; 
1.14      daniel   1098:     cur->parent = NULL; 
1.23      daniel   1099:     cur->prev = NULL; 
1.14      daniel   1100:     cur->next = NULL; 
                   1101:     cur->childs = NULL; 
1.32      daniel   1102:     cur->last = NULL; 
1.14      daniel   1103:     cur->properties = NULL; 
1.23      daniel   1104:     cur->type = XML_COMMENT_NODE;
1.18      daniel   1105:     cur->name = xmlStrdup(xmlStringText);
1.16      daniel   1106:     cur->ns = NULL;
1.19      daniel   1107:     cur->nsDef = NULL;
1.14      daniel   1108:     if (content != NULL)
                   1109:        cur->content = xmlStrdup(content);
                   1110:     else 
                   1111:        cur->content = NULL;
                   1112:     return(cur);
                   1113: }
                   1114: 
1.23      daniel   1115: /**
                   1116:  * xmlNewComment:
                   1117:  * @doc:  the document
                   1118:  * @content:  the comment content
                   1119:  *
                   1120:  * Creation of a new node containing a commentwithin a document.
                   1121:  * return values: a pointer to the new node object.
                   1122:  */
1.28      daniel   1123: xmlNodePtr
                   1124: xmlNewDocComment(xmlDocPtr doc, CHAR *content) {
1.23      daniel   1125:     xmlNodePtr cur;
                   1126: 
                   1127:     cur = xmlNewComment(content);
                   1128:     if (cur != NULL) cur->doc = doc;
                   1129:     return(cur);
                   1130: }
                   1131: 
                   1132: /**
                   1133:  * xmlNewChild:
                   1134:  * @parent:  the parent node
                   1135:  * @ns:  a namespace if any
                   1136:  * @name:  the name of the child
                   1137:  * @content:  the content of the child if any.
                   1138:  *
                   1139:  * 
                   1140:  * Creation of a new child element, added at the end of @parent childs list.
1.24      daniel   1141:  * @ns and @content parameters are optionnal (NULL). If content is non NULL,
                   1142:  * a child list containing the TEXTs and ENTITY_REFs node will be created.
1.23      daniel   1143:  * return values: a pointer to the new node object.
1.1       veillard 1144:  */
1.28      daniel   1145: xmlNodePtr
                   1146: xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1.7       veillard 1147:                        const CHAR *name, CHAR *content) {
1.1       veillard 1148:     xmlNodePtr cur, prev;
                   1149: 
                   1150:     if (parent == NULL) {
                   1151:         fprintf(stderr, "xmlNewChild : parent == NULL\n");
                   1152:        return(NULL);
                   1153:     }
                   1154: 
                   1155:     if (name == NULL) {
                   1156:         fprintf(stderr, "xmlNewChild : name == NULL\n");
                   1157:        return(NULL);
                   1158:     }
                   1159: 
                   1160:     /*
                   1161:      * Allocate a new node
                   1162:      */
1.16      daniel   1163:     if (ns == NULL)
1.24      daniel   1164:        cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1.1       veillard 1165:     else
1.24      daniel   1166:        cur = xmlNewDocNode(parent->doc, ns, name, content);
1.1       veillard 1167:     if (cur == NULL) return(NULL);
                   1168: 
                   1169:     /*
                   1170:      * add the new element at the end of the childs list.
                   1171:      */
1.25      daniel   1172:     cur->type = XML_ELEMENT_NODE;
1.1       veillard 1173:     cur->parent = parent;
1.23      daniel   1174:     cur->doc = parent->doc;
1.1       veillard 1175:     if (parent->childs == NULL) {
                   1176:         parent->childs = cur;
1.32      daniel   1177:        parent->last = cur;
1.1       veillard 1178:     } else {
1.32      daniel   1179:         prev = parent->last;
1.1       veillard 1180:        prev->next = cur;
1.23      daniel   1181:        cur->prev = prev;
1.32      daniel   1182:        parent->last = cur;
1.1       veillard 1183:     }
                   1184: 
                   1185:     return(cur);
                   1186: }
                   1187: 
1.23      daniel   1188: /**
                   1189:  * xmlAddChild:
                   1190:  * @parent:  the parent node
                   1191:  * @cur:  the child node
                   1192:  *
                   1193:  * Add a new child element, to @parent, at the end of the child list.
                   1194:  * return values: the child or NULL in case of error.
1.2       veillard 1195:  */
1.28      daniel   1196: xmlNodePtr
                   1197: xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
1.2       veillard 1198:     xmlNodePtr prev;
                   1199: 
                   1200:     if (parent == NULL) {
                   1201:         fprintf(stderr, "xmladdChild : parent == NULL\n");
                   1202:        return(NULL);
                   1203:     }
                   1204: 
                   1205:     if (cur == NULL) {
                   1206:         fprintf(stderr, "xmladdChild : child == NULL\n");
                   1207:        return(NULL);
                   1208:     }
                   1209: 
1.23      daniel   1210:     if ((cur->doc != NULL) && (parent->doc != NULL) &&
                   1211:         (cur->doc != parent->doc)) {
                   1212:        fprintf(stderr, "Elements moved to a different document\n");
                   1213:     }
                   1214: 
1.2       veillard 1215:     /*
                   1216:      * add the new element at the end of the childs list.
                   1217:      */
                   1218:     cur->parent = parent;
1.23      daniel   1219:     cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
1.32      daniel   1220: 
1.24      daniel   1221:     /*
                   1222:      * Handle the case where parent->content != NULL, in that case it will
                   1223:      * create a intermediate TEXT node.
                   1224:      */
                   1225:     if (parent->content != NULL) {
                   1226:         xmlNodePtr text;
                   1227:        
                   1228:        text = xmlNewDocText(parent->doc, parent->content);
                   1229:        if (text != NULL) {
                   1230:            text->next = parent->childs;
                   1231:            if (text->next != NULL)
                   1232:                text->next->prev = text;
                   1233:            parent->childs = text;
1.32      daniel   1234:            UPDATE_LAST_CHILD(parent);
1.24      daniel   1235:            free(parent->content);
                   1236:            parent->content = NULL;
                   1237:        }
                   1238:     }
1.2       veillard 1239:     if (parent->childs == NULL) {
                   1240:         parent->childs = cur;
1.32      daniel   1241:        parent->last = cur;
1.2       veillard 1242:     } else {
1.32      daniel   1243:         prev = parent->last;
1.2       veillard 1244:        prev->next = cur;
1.23      daniel   1245:        cur->prev = prev;
1.32      daniel   1246:        parent->last = cur;
1.2       veillard 1247:     }
                   1248: 
                   1249:     return(cur);
                   1250: }
                   1251: 
1.23      daniel   1252: /**
                   1253:  * xmlGetLastChild:
                   1254:  * @parent:  the parent node
                   1255:  *
                   1256:  * Search the last child of a node.
                   1257:  * return values: the last child or NULL if none.
1.21      daniel   1258:  */
1.28      daniel   1259: xmlNodePtr
                   1260: xmlGetLastChild(xmlNodePtr parent) {
1.21      daniel   1261:     if (parent == NULL) {
                   1262:         fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
                   1263:        return(NULL);
                   1264:     }
1.32      daniel   1265:     return(parent->last);
1.21      daniel   1266: }
                   1267: 
1.23      daniel   1268: /**
                   1269:  * xmlFreeNodeList:
                   1270:  * @cur:  the first node in the list
                   1271:  *
                   1272:  * Free a node and all its siblings, this is a recursive behaviour, all
                   1273:  * the childs are freed too.
1.1       veillard 1274:  */
1.28      daniel   1275: void
                   1276: xmlFreeNodeList(xmlNodePtr cur) {
1.1       veillard 1277:     xmlNodePtr next;
                   1278:     if (cur == NULL) {
                   1279:         fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
                   1280:        return;
                   1281:     }
                   1282:     while (cur != NULL) {
                   1283:         next = cur->next;
                   1284:         xmlFreeNode(cur);
                   1285:        cur = next;
                   1286:     }
                   1287: }
                   1288: 
1.23      daniel   1289: /**
                   1290:  * xmlFreeNode:
                   1291:  * @cur:  the node
                   1292:  *
                   1293:  * Free a node, this is a recursive behaviour, all the childs are freed too.
1.1       veillard 1294:  */
1.28      daniel   1295: void
                   1296: xmlFreeNode(xmlNodePtr cur) {
1.1       veillard 1297:     if (cur == NULL) {
                   1298:         fprintf(stderr, "xmlFreeNode : node == NULL\n");
                   1299:        return;
                   1300:     }
1.23      daniel   1301:     cur->doc = NULL;
                   1302:     cur->parent = NULL;
                   1303:     cur->next = NULL;
                   1304:     cur->prev = NULL;
                   1305:     if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
1.1       veillard 1306:     if (cur->properties != NULL) xmlFreePropList(cur->properties);
1.23      daniel   1307:     if (cur->type != XML_ENTITY_REF_NODE)
                   1308:        if (cur->content != NULL) free(cur->content);
1.7       veillard 1309:     if (cur->name != NULL) free((char *) cur->name);
1.19      daniel   1310:     if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1.1       veillard 1311:     memset(cur, -1, sizeof(xmlNode));
                   1312:     free(cur);
                   1313: }
                   1314: 
1.28      daniel   1315: /**
                   1316:  * xmlUnlinkNode:
                   1317:  * @cur:  the node
                   1318:  *
                   1319:  * Unlink a node from it's current context, the node is not freed
                   1320:  */
                   1321: void
                   1322: xmlUnlinkNode(xmlNodePtr cur) {
                   1323:     if (cur == NULL) {
                   1324:         fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
                   1325:        return;
                   1326:     }
                   1327:     if ((cur->parent != NULL) && (cur->parent->childs == cur))
                   1328:         cur->parent->childs = cur->next;
1.32      daniel   1329:     if ((cur->parent != NULL) && (cur->parent->last == cur))
                   1330:         cur->parent->last = cur->prev;
1.28      daniel   1331:     if (cur->next != NULL)
                   1332:         cur->next->prev = cur->prev;
                   1333:     if (cur->prev != NULL)
                   1334:         cur->prev->next = cur->next;
                   1335:     cur->next = cur->prev = NULL;
                   1336:     cur->parent = NULL;
                   1337: }
                   1338: 
1.1       veillard 1339: /************************************************************************
                   1340:  *                                                                     *
1.31      daniel   1341:  *             Copy operations                                         *
                   1342:  *                                                                     *
                   1343:  ************************************************************************/
                   1344:  
                   1345: /**
                   1346:  * xmlCopyNamespace:
                   1347:  * @cur:  the namespace
                   1348:  *
                   1349:  * Do a copy of the namespace.
                   1350:  *
                   1351:  * Returns: a new xmlNsPtr, or NULL in case of error.
                   1352:  */
                   1353: xmlNsPtr
                   1354: xmlCopyNamespace(xmlNsPtr cur) {
                   1355:     xmlNsPtr ret;
                   1356: 
                   1357:     if (cur == NULL) return(NULL);
                   1358:     switch (cur->type) {
                   1359:         case XML_GLOBAL_NAMESPACE:
                   1360:            ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
                   1361:            break;
                   1362:        case XML_LOCAL_NAMESPACE:
                   1363:            ret = xmlNewNs(NULL, cur->href, cur->prefix);
                   1364:            break;
                   1365:        default:
                   1366:            fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
                   1367:            return(NULL);
                   1368:     }
                   1369:     return(ret);
                   1370: }
                   1371: 
                   1372: /**
                   1373:  * xmlCopyNamespaceList:
                   1374:  * @cur:  the first namespace
                   1375:  *
                   1376:  * Do a copy of an namespace list.
                   1377:  *
                   1378:  * Returns: a new xmlNsPtr, or NULL in case of error.
                   1379:  */
                   1380: xmlNsPtr
                   1381: xmlCopyNamespaceList(xmlNsPtr cur) {
                   1382:     xmlNsPtr ret = NULL;
                   1383:     xmlNsPtr p = NULL,q;
                   1384: 
                   1385:     while (cur != NULL) {
                   1386:         q = xmlCopyNamespace(cur);
                   1387:        if (p == NULL) {
                   1388:            ret = p = q;
                   1389:        } else {
                   1390:            p->next = q;
                   1391:            p = q;
                   1392:        }
                   1393:        cur = cur->next;
                   1394:     }
                   1395:     return(ret);
                   1396: }
                   1397: 
                   1398: /**
                   1399:  * xmlCopyProp:
                   1400:  * @cur:  the attribute
                   1401:  *
                   1402:  * Do a copy of the attribute.
                   1403:  *
                   1404:  * Returns: a new xmlAttrPtr, or NULL in case of error.
                   1405:  */
                   1406: xmlAttrPtr
                   1407: xmlCopyProp(xmlAttrPtr cur) {
                   1408:     xmlAttrPtr ret;
                   1409: 
                   1410:     if (cur == NULL) return(NULL);
                   1411:     if (cur->val != NULL)
                   1412:        ret = xmlNewDocProp(cur->val->doc, cur->name, NULL);
                   1413:     else
                   1414:        ret = xmlNewDocProp(NULL, cur->name, NULL);
                   1415:     if (ret == NULL) return(NULL);
                   1416:     if (cur->val != NULL)
                   1417:        ret->val = xmlCopyNodeList(cur->val);
                   1418:     return(ret);
                   1419: }
                   1420: 
                   1421: /**
                   1422:  * xmlCopyPropList:
                   1423:  * @cur:  the first attribute
                   1424:  *
                   1425:  * Do a copy of an attribute list.
                   1426:  *
                   1427:  * Returns: a new xmlAttrPtr, or NULL in case of error.
                   1428:  */
                   1429: xmlAttrPtr
                   1430: xmlCopyPropList(xmlAttrPtr cur) {
                   1431:     xmlAttrPtr ret = NULL;
                   1432:     xmlAttrPtr p = NULL,q;
                   1433: 
                   1434:     while (cur != NULL) {
                   1435:         q = xmlCopyProp(cur);
                   1436:        if (p == NULL) {
                   1437:            ret = p = q;
                   1438:        } else {
                   1439:            p->next = q;
                   1440:            p = q;
                   1441:        }
                   1442:        cur = cur->next;
                   1443:     }
                   1444:     return(ret);
                   1445: }
                   1446: 
                   1447: /*
                   1448:  * NOTE about the CopyNode operations !
                   1449:  *
                   1450:  * They are splitted into external and internal parts for one
                   1451:  * tricky reason: namespaces. Doing a direct copy of a node
                   1452:  * say RPM:Copyright without changing the namespace pointer to
                   1453:  * something else can produce stale links. One way to do it is
                   1454:  * to keep a reference counter but this doesn't work as soon
                   1455:  * as one move the element or the subtree out of the scope of
                   1456:  * the existing namespace. The actual solution seems to add
                   1457:  * a copy of the namespace at the top of the copied tree if
                   1458:  * not available in the subtree.
                   1459:  * Hence two functions, the public front-end call the inner ones
                   1460:  */
                   1461: 
                   1462: static xmlNodePtr
                   1463: xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
                   1464: 
                   1465: static xmlNodePtr
                   1466: xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
                   1467:                   int recursive) {
                   1468:     xmlNodePtr ret;
                   1469: 
                   1470:     if (node == NULL) return(NULL);
                   1471:     /*
                   1472:      * Allocate a new node and fill the fields.
                   1473:      */
                   1474:     ret = (xmlNodePtr) malloc(sizeof(xmlNode));
                   1475:     if (ret == NULL) {
                   1476:         fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
                   1477:        return(NULL);
                   1478:     }
                   1479: 
                   1480:     ret->type = node->type;
                   1481:     ret->doc = doc;
                   1482:     ret->parent = parent; 
                   1483:     ret->next = NULL;
                   1484:     ret->prev = NULL;
                   1485:     ret->childs = NULL;
1.32      daniel   1486:     ret->last = NULL;
1.31      daniel   1487:     ret->properties = NULL;
                   1488:     if (node->name != NULL)
                   1489:        ret->name = xmlStrdup(node->name);
                   1490:     else
                   1491:         ret->name = NULL;
                   1492:     ret->ns = NULL;
                   1493:     ret->nsDef = NULL;
                   1494:     if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE))
                   1495:        ret->content = xmlStrdup(node->content);
                   1496:     else
                   1497:        ret->content = NULL;
                   1498: #ifndef WITHOUT_CORBA
                   1499:     ret->_private = NULL;
                   1500:     ret->vepv = NULL;
                   1501: #endif
                   1502:     if (parent != NULL)
                   1503:         xmlAddChild(parent, ret);
                   1504:     
                   1505:     if (!recursive) return(ret);
                   1506:     if (node->properties != NULL)
                   1507:         ret->properties = xmlCopyPropList(node->properties);
                   1508:     if (node->nsDef != NULL)
                   1509:         ret->nsDef = xmlCopyNamespaceList(node->nsDef);
                   1510: 
                   1511:     if (node->ns != NULL) {
                   1512:         xmlNsPtr ns;
                   1513: 
                   1514:        ns = xmlSearchNs(doc, ret, node->ns->prefix);
                   1515:        if (ns == NULL) {
                   1516:            /*
                   1517:             * Humm, we are copying an element whose namespace is defined
                   1518:             * out of the new tree scope. Search it in the original tree
                   1519:             * and add it at the top of the new tree
                   1520:             */
                   1521:            ns = xmlSearchNs(node->doc, node, node->ns->prefix);
                   1522:            if (ns != NULL) {
                   1523:                xmlNodePtr root = ret;
                   1524: 
                   1525:                while (root->parent != NULL) root = root->parent;
                   1526:                xmlNewNs(root, ns->href, ns->prefix);
                   1527:            }
                   1528:        } else {
                   1529:            /*
                   1530:             * reference the existing namespace definition in our own tree.
                   1531:             */
                   1532:            ret->ns = ns;
                   1533:        }
                   1534:     }
                   1535:     if (node->childs != NULL)
                   1536:         ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
1.32      daniel   1537:     UPDATE_LAST_CHILD(ret);
1.31      daniel   1538:     return(ret);
                   1539: }
                   1540: 
                   1541: static xmlNodePtr
                   1542: xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
                   1543:     xmlNodePtr ret = NULL;
                   1544:     xmlNodePtr p = NULL,q;
                   1545: 
                   1546:     while (node != NULL) {
                   1547:         q = xmlStaticCopyNode(node, doc, parent, 1);
                   1548:        if (parent == NULL) {
                   1549:            if (ret == NULL) ret = q;
                   1550:        } else {
                   1551:            if (ret == NULL) {
                   1552:                q->prev = NULL;
                   1553:                ret = p = q;
                   1554:            } else {
                   1555:                p->next = q;
                   1556:                q->prev = p;
                   1557:                p = q;
                   1558:            }
                   1559:        }
                   1560:        node = node->next;
                   1561:     }
                   1562:     return(ret);
                   1563: }
                   1564: 
                   1565: /**
                   1566:  * xmlCopyNode:
                   1567:  * @node:  the node
                   1568:  * @recursive:  if 1 do a recursive copy.
                   1569:  *
                   1570:  * Do a copy of the node.
                   1571:  *
                   1572:  * Returns: a new xmlNodePtr, or NULL in case of error.
                   1573:  */
                   1574: xmlNodePtr
                   1575: xmlCopyNode(xmlNodePtr node, int recursive) {
                   1576:     xmlNodePtr ret;
                   1577: 
                   1578:     ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
                   1579:     return(ret);
                   1580: }
                   1581: 
                   1582: /**
                   1583:  * xmlCopyNodeList:
                   1584:  * @node:  the first node in the list.
                   1585:  *
                   1586:  * Do a recursive copy of the node list.
                   1587:  *
                   1588:  * Returns: a new xmlNodePtr, or NULL in case of error.
                   1589:  */
                   1590: xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
                   1591:     xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
                   1592:     return(ret);
                   1593: }
                   1594: 
                   1595: /**
                   1596:  * xmlCopyElement:
                   1597:  * @elem:  the element
                   1598:  *
                   1599:  * Do a copy of the element definition.
                   1600:  *
                   1601:  * Returns: a new xmlElementPtr, or NULL in case of error.
                   1602: xmlElementPtr
                   1603: xmlCopyElement(xmlElementPtr elem) {
                   1604:     xmlElementPtr ret;
                   1605: 
                   1606:     if (elem == NULL) return(NULL);
                   1607:     ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
                   1608:     if (ret == NULL) return(NULL);
                   1609:     if (!recursive) return(ret);
                   1610:     if (elem->properties != NULL)
                   1611:         ret->properties = xmlCopyPropList(elem->properties);
                   1612:     
                   1613:     if (elem->nsDef != NULL)
                   1614:         ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
                   1615:     if (elem->childs != NULL)
                   1616:         ret->childs = xmlCopyElementList(elem->childs);
                   1617:     return(ret);
                   1618: }
                   1619:  */
                   1620: 
                   1621: /**
                   1622:  * xmlCopyDtd:
                   1623:  * @dtd:  the dtd
                   1624:  *
                   1625:  * Do a copy of the dtd.
                   1626:  *
                   1627:  * Returns: a new xmlDtdPtr, or NULL in case of error.
                   1628:  */
                   1629: xmlDtdPtr
                   1630: xmlCopyDtd(xmlDtdPtr dtd) {
                   1631:     xmlDtdPtr ret;
                   1632: 
                   1633:     if (dtd == NULL) return(NULL);
                   1634:     ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
                   1635:     if (ret == NULL) return(NULL);
                   1636:     if (dtd->entities != NULL)
                   1637:         ret->entities = (void *) xmlCopyEntitiesTable(
                   1638:                            (xmlEntitiesTablePtr) dtd->entities);
                   1639:     /*
                   1640:      * TODO: support for Element definitions.
                   1641:      */
                   1642:     return(ret);
                   1643: }
                   1644: 
                   1645: /**
                   1646:  * xmlCopyDoc:
                   1647:  * @doc:  the document
                   1648:  * @recursive:  if 1 do a recursive copy.
                   1649:  *
                   1650:  * Do a copy of the document info. If recursive, the content tree will
                   1651:  * be copied too as well as Dtd, namespaces and entities.
                   1652:  *
                   1653:  * Returns: a new xmlDocPtr, or NULL in case of error.
                   1654:  */
                   1655: xmlDocPtr
                   1656: xmlCopyDoc(xmlDocPtr doc, int recursive) {
                   1657:     xmlDocPtr ret;
                   1658: 
                   1659:     if (doc == NULL) return(NULL);
                   1660:     ret = xmlNewDoc(doc->version);
                   1661:     if (ret == NULL) return(NULL);
                   1662:     if (doc->name != NULL)
                   1663:         ret->name = strdup(doc->name);
                   1664:     if (doc->encoding != NULL)
                   1665:         ret->encoding = xmlStrdup(doc->encoding);
                   1666:     ret->compression = doc->compression;
                   1667:     ret->standalone = doc->standalone;
                   1668:     if (!recursive) return(ret);
                   1669: 
                   1670:     if (doc->intSubset != NULL)
                   1671:         ret->intSubset = xmlCopyDtd(doc->intSubset);
                   1672:     if (doc->oldNs != NULL)
                   1673:         ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
                   1674:     if (doc->root != NULL)
                   1675:         ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL);
                   1676:     return(ret);
                   1677: }
                   1678: 
                   1679: /************************************************************************
                   1680:  *                                                                     *
1.1       veillard 1681:  *             Content access functions                                *
                   1682:  *                                                                     *
                   1683:  ************************************************************************/
                   1684:  
1.23      daniel   1685: /**
1.28      daniel   1686:  * xmlNodeGetContent:
                   1687:  * @cur:  the node being read
                   1688:  *
                   1689:  * Read the value of a node, this can be either the text carried
                   1690:  * directly by this node if it's a TEXT node or the aggregate string
                   1691:  * of the values carried by this node child's (TEXT and ENTITY_REF).
                   1692:  * Entity references are substitued.
                   1693:  * Return value: a new CHAR * or NULL if no content is available.
                   1694:  */
                   1695: CHAR *
                   1696: xmlNodeGetContent(xmlNodePtr cur) {
                   1697:     if (cur == NULL) return(NULL);
                   1698:     switch (cur->type) {
                   1699:         case XML_DOCUMENT_FRAG_NODE:
                   1700:         case XML_ELEMENT_NODE:
                   1701:             return(xmlNodeListGetString(cur->doc, cur->childs, 1));
                   1702:            break;
                   1703:         case XML_ATTRIBUTE_NODE:
                   1704:         case XML_CDATA_SECTION_NODE:
                   1705:         case XML_ENTITY_REF_NODE:
                   1706:         case XML_ENTITY_NODE:
                   1707:         case XML_PI_NODE:
                   1708:         case XML_COMMENT_NODE:
                   1709:         case XML_DOCUMENT_NODE:
                   1710:         case XML_DOCUMENT_TYPE_NODE:
                   1711:         case XML_NOTATION_NODE:
                   1712:            return(NULL);
                   1713:         case XML_TEXT_NODE:
                   1714:            if (cur->content != NULL)
                   1715:                return(xmlStrdup(cur->content));
                   1716:             return(NULL);
                   1717:     }
                   1718:     return(NULL);
                   1719: }
                   1720:  
                   1721: /**
1.23      daniel   1722:  * xmlNodeSetContent:
                   1723:  * @cur:  the node being modified
                   1724:  * @content:  the new value of the content
                   1725:  *
                   1726:  * Replace the content of a node.
1.1       veillard 1727:  */
1.28      daniel   1728: void
                   1729: xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
1.1       veillard 1730:     if (cur == NULL) {
                   1731:         fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
                   1732:        return;
                   1733:     }
1.28      daniel   1734:     switch (cur->type) {
                   1735:         case XML_DOCUMENT_FRAG_NODE:
                   1736:         case XML_ELEMENT_NODE:
                   1737:            if (cur->content != NULL) {
                   1738:                free(cur->content);
                   1739:                cur->content = NULL;
                   1740:            }
                   1741:            if (cur->childs != NULL) xmlFreeNode(cur->childs);
                   1742:            cur->childs = xmlStringGetNodeList(cur->doc, content);
1.32      daniel   1743:            UPDATE_LAST_CHILD(cur);
1.28      daniel   1744:            break;
                   1745:         case XML_ATTRIBUTE_NODE:
                   1746:            break;
                   1747:         case XML_TEXT_NODE:
                   1748:         case XML_CDATA_SECTION_NODE:
                   1749:         case XML_ENTITY_REF_NODE:
                   1750:         case XML_ENTITY_NODE:
                   1751:         case XML_PI_NODE:
                   1752:         case XML_COMMENT_NODE:
                   1753:            if (cur->content != NULL) free(cur->content);
                   1754:            if (cur->childs != NULL) xmlFreeNode(cur->childs);
1.32      daniel   1755:            cur->last = cur->childs = NULL;
1.28      daniel   1756:            if (content != NULL)
                   1757:                cur->content = xmlStrdup(content);
                   1758:            else 
                   1759:                cur->content = NULL;
                   1760:         case XML_DOCUMENT_NODE:
                   1761:         case XML_DOCUMENT_TYPE_NODE:
                   1762:            break;
                   1763:         case XML_NOTATION_NODE:
                   1764:            break;
                   1765:     }
1.1       veillard 1766: }
                   1767: 
1.23      daniel   1768: /**
                   1769:  * xmlNodeSetContentLen:
                   1770:  * @cur:  the node being modified
                   1771:  * @content:  the new value of the content
                   1772:  * @len:  the size of @content
                   1773:  *
                   1774:  * Replace the content of a node.
1.21      daniel   1775:  */
1.28      daniel   1776: void
                   1777: xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
1.21      daniel   1778:     if (cur == NULL) {
1.28      daniel   1779:         fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
1.21      daniel   1780:        return;
                   1781:     }
1.28      daniel   1782:     switch (cur->type) {
                   1783:         case XML_DOCUMENT_FRAG_NODE:
                   1784:         case XML_ELEMENT_NODE:
                   1785:            if (cur->content != NULL) {
                   1786:                free(cur->content);
                   1787:                cur->content = NULL;
                   1788:            }
                   1789:            if (cur->childs != NULL) xmlFreeNode(cur->childs);
                   1790:            cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
1.32      daniel   1791:            UPDATE_LAST_CHILD(cur);
1.28      daniel   1792:            break;
                   1793:         case XML_ATTRIBUTE_NODE:
                   1794:            break;
                   1795:         case XML_TEXT_NODE:
                   1796:         case XML_CDATA_SECTION_NODE:
                   1797:         case XML_ENTITY_REF_NODE:
                   1798:         case XML_ENTITY_NODE:
                   1799:         case XML_PI_NODE:
                   1800:         case XML_COMMENT_NODE:
                   1801:            if (cur->content != NULL) free(cur->content);
                   1802:            if (cur->childs != NULL) xmlFreeNode(cur->childs);
1.32      daniel   1803:            cur->childs = cur->last = NULL;
1.28      daniel   1804:            if (content != NULL)
                   1805:                cur->content = xmlStrndup(content, len);
                   1806:            else 
                   1807:                cur->content = NULL;
                   1808:         case XML_DOCUMENT_NODE:
                   1809:         case XML_DOCUMENT_TYPE_NODE:
                   1810:            break;
                   1811:         case XML_NOTATION_NODE:
                   1812:            if (cur->content != NULL) free(cur->content);
1.32      daniel   1813:            if (cur->childs != NULL) xmlFreeNode(cur->childs);
                   1814:            cur->childs = cur->last = NULL;
1.28      daniel   1815:            if (content != NULL)
                   1816:                cur->content = xmlStrndup(content, len);
                   1817:            else 
                   1818:                cur->content = NULL;
                   1819:            break;
                   1820:     }
1.21      daniel   1821: }
                   1822: 
1.23      daniel   1823: /**
1.28      daniel   1824:  * xmlNodeAddContentLen:
1.23      daniel   1825:  * @cur:  the node being modified
                   1826:  * @content:  extra content
1.28      daniel   1827:  * @len:  the size of @content
1.23      daniel   1828:  * 
                   1829:  * Append the extra substring to the node content.
1.21      daniel   1830:  */
1.28      daniel   1831: void
                   1832: xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
1.21      daniel   1833:     if (cur == NULL) {
1.28      daniel   1834:         fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1.21      daniel   1835:        return;
                   1836:     }
1.28      daniel   1837:     if (len <= 0) return;
                   1838:     switch (cur->type) {
                   1839:         case XML_DOCUMENT_FRAG_NODE:
                   1840:         case XML_ELEMENT_NODE: {
                   1841:            xmlNodePtr last = NULL, new;
                   1842: 
                   1843:            if (cur->childs != NULL) {
1.32      daniel   1844:                last = cur->last;
1.28      daniel   1845:            } else {
                   1846:                if (cur->content != NULL) {
                   1847:                    cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
1.32      daniel   1848:                    UPDATE_LAST_CHILD(cur);
1.28      daniel   1849:                    free(cur->content);
                   1850:                    cur->content = NULL;
1.32      daniel   1851:                    last = cur->last;
1.28      daniel   1852:                }
                   1853:            }
1.31      daniel   1854:            new = xmlNewTextLen(content, len);
1.28      daniel   1855:            if (new != NULL) {
                   1856:                xmlAddChild(cur, new);
1.32      daniel   1857:                if ((last != NULL) && (last->next == new)) {
1.28      daniel   1858:                    xmlTextMerge(last, new);
1.32      daniel   1859:                }
1.28      daniel   1860:            }
                   1861:            break;
                   1862:        }
                   1863:         case XML_ATTRIBUTE_NODE:
                   1864:            break;
                   1865:         case XML_TEXT_NODE:
                   1866:         case XML_CDATA_SECTION_NODE:
                   1867:         case XML_ENTITY_REF_NODE:
                   1868:         case XML_ENTITY_NODE:
                   1869:         case XML_PI_NODE:
                   1870:         case XML_COMMENT_NODE:
                   1871:            if (content != NULL)
                   1872:                cur->content = xmlStrncat(cur->content, content, len);
                   1873:         case XML_DOCUMENT_NODE:
                   1874:         case XML_DOCUMENT_TYPE_NODE:
                   1875:            break;
                   1876:         case XML_NOTATION_NODE:
                   1877:            if (content != NULL)
                   1878:                cur->content = xmlStrncat(cur->content, content, len);
                   1879:            break;
                   1880:     }
1.21      daniel   1881: }
                   1882: 
1.23      daniel   1883: /**
1.28      daniel   1884:  * xmlNodeAddContent:
1.23      daniel   1885:  * @cur:  the node being modified
                   1886:  * @content:  extra content
                   1887:  * 
                   1888:  * Append the extra substring to the node content.
1.21      daniel   1889:  */
1.28      daniel   1890: void
                   1891: xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
                   1892:     int len;
                   1893: 
1.21      daniel   1894:     if (cur == NULL) {
                   1895:         fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
                   1896:        return;
                   1897:     }
1.28      daniel   1898:     if (content == NULL) return;
                   1899:     len = xmlStrlen(content);
                   1900:     xmlNodeAddContentLen(cur, content, len);
                   1901: }
                   1902: 
                   1903: /**
                   1904:  * xmlTextMerge:
                   1905:  * @first:  the first text node
                   1906:  * @second:  the second text node being merged
                   1907:  * 
                   1908:  * Merge two text nodes into one
                   1909:  * Return values: the first text node augmented
                   1910:  */
                   1911: xmlNodePtr
                   1912: xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
                   1913:     if (first == NULL) return(second);
                   1914:     if (second == NULL) return(first);
                   1915:     if (first->type != XML_TEXT_NODE) return(first);
                   1916:     if (second->type != XML_TEXT_NODE) return(first);
                   1917:     xmlNodeAddContent(first, second->content);
                   1918:     xmlUnlinkNode(second);
                   1919:     xmlFreeNode(second);
                   1920:     return(first);
1.21      daniel   1921: }
                   1922: 
1.23      daniel   1923: /**
                   1924:  * xmlSearchNs:
                   1925:  * @doc:  the document
                   1926:  * @node:  the current node
                   1927:  * @nameSpace:  the namespace string
                   1928:  *
1.16      daniel   1929:  * Search a Ns registered under a given name space for a document.
1.23      daniel   1930:  * recurse on the parents until it finds the defined namespace
                   1931:  * or return NULL otherwise.
                   1932:  * @nameSpace can be NULL, this is a search for the default namespace.
                   1933:  * return values: the namespace pointer or NULL.
1.3       veillard 1934:  */
1.28      daniel   1935: xmlNsPtr
                   1936: xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
1.16      daniel   1937:     xmlNsPtr cur;
1.3       veillard 1938: 
1.19      daniel   1939:     while (node != NULL) {
                   1940:        cur = node->nsDef;
                   1941:        while (cur != NULL) {
                   1942:            if ((cur->prefix == NULL) && (nameSpace == NULL))
                   1943:                return(cur);
                   1944:            if ((cur->prefix != NULL) && (nameSpace != NULL) &&
                   1945:                (!xmlStrcmp(cur->prefix, nameSpace)))
                   1946:                return(cur);
                   1947:            cur = cur->next;
                   1948:        }
                   1949:        node = node->parent;
                   1950:     }
                   1951:     if (doc != NULL) {
                   1952:         cur = doc->oldNs;
                   1953:        while (cur != NULL) {
                   1954:            if ((cur->prefix != NULL) && (nameSpace != NULL) &&
                   1955:                (!xmlStrcmp(cur->prefix, nameSpace)))
                   1956:                return(cur);
                   1957:            cur = cur->next;
                   1958:        }
                   1959:     }
                   1960:     return(NULL);
                   1961: }
1.3       veillard 1962: 
1.23      daniel   1963: /**
                   1964:  * xmlSearchNsByHref:
                   1965:  * @doc:  the document
                   1966:  * @node:  the current node
                   1967:  * @href:  the namespace value
                   1968:  *
                   1969:  * Search a Ns aliasing a given URI. Recurse on the parents until it finds
                   1970:  * the defined namespace or return NULL otherwise.
                   1971:  * return values: the namespace pointer or NULL.
1.19      daniel   1972:  */
1.28      daniel   1973: xmlNsPtr
                   1974: xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
1.19      daniel   1975:     xmlNsPtr cur;
                   1976: 
                   1977:     while (node != NULL) {
                   1978:        cur = node->nsDef;
                   1979:        while (cur != NULL) {
                   1980:            if ((cur->href != NULL) && (href != NULL) &&
                   1981:                (!xmlStrcmp(cur->href, href)))
                   1982:                return(cur);
                   1983:            cur = cur->next;
                   1984:        }
                   1985:        node = node->parent;
                   1986:     }
                   1987:     if (doc != NULL) {
                   1988:         cur = doc->oldNs;
                   1989:        while (cur != NULL) {
                   1990:            if ((cur->href != NULL) && (href != NULL) &&
                   1991:                (!xmlStrcmp(cur->href, href)))
                   1992:                return(cur);
                   1993:            cur = cur->next;
                   1994:        }
1.3       veillard 1995:     }
                   1996:     return(NULL);
                   1997: }
                   1998: 
1.23      daniel   1999: /**
                   2000:  * xmlGetProp:
                   2001:  * @node:  the node
                   2002:  * @name:  the attribute name
                   2003:  *
                   2004:  * Search and get the value of an attribute associated to a node
                   2005:  * This does the entity substitution.
                   2006:  * return values: the attribute value or NULL if not found.
1.9       veillard 2007:  */
1.31      daniel   2008: CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
1.20      daniel   2009:     xmlAttrPtr prop = node->properties;
1.9       veillard 2010: 
                   2011:     while (prop != NULL) {
1.23      daniel   2012:         if (!xmlStrcmp(prop->name, name)) 
1.24      daniel   2013:            return(xmlNodeListGetString(node->doc, prop->val, 1));
1.9       veillard 2014:        prop = prop->next;
                   2015:     }
1.10      veillard 2016:     return(NULL);
1.13      daniel   2017: }
                   2018: 
1.23      daniel   2019: /**
                   2020:  * xmlSetProp:
                   2021:  * @node:  the node
                   2022:  * @name:  the attribute name
                   2023:  * @value:  the attribute value
                   2024:  *
                   2025:  * Set (or reset) an attribute carried by a node.
                   2026:  * return values: the attribute pointer.
1.13      daniel   2027:  */
1.28      daniel   2028: xmlAttrPtr
                   2029: xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
1.20      daniel   2030:     xmlAttrPtr prop = node->properties;
1.13      daniel   2031: 
                   2032:     while (prop != NULL) {
                   2033:         if (!xmlStrcmp(prop->name, name)) {
1.23      daniel   2034:            if (prop->val != NULL) 
                   2035:                xmlFreeNode(prop->val);
                   2036:            prop->val = NULL;
1.13      daniel   2037:            if (value != NULL)
1.24      daniel   2038:                prop->val = xmlStringGetNodeList(node->doc, value);
1.13      daniel   2039:            return(prop);
                   2040:        }
                   2041:        prop = prop->next;
                   2042:     }
                   2043:     prop = xmlNewProp(node, name, value);
                   2044:     return(prop);
1.9       veillard 2045: }
                   2046: 
1.23      daniel   2047: /**
                   2048:  * xmlNodeIsText:
                   2049:  * @node:  the node
                   2050:  * 
                   2051:  * Is this node a Text node ?
                   2052:  * return values: 1 yes, 0 no
1.21      daniel   2053:  */
1.28      daniel   2054: int
                   2055: xmlNodeIsText(xmlNodePtr node) {
1.21      daniel   2056:     if (node == NULL) return(0);
                   2057: 
1.23      daniel   2058:     if (node->type == XML_TEXT_NODE) return(1);
1.21      daniel   2059:     return(0);
                   2060: }
                   2061: 
1.23      daniel   2062: /**
                   2063:  * xmlNodeIsText:
                   2064:  * @node:  the node
                   2065:  * @content:  the content
                   2066:  * @len:  @content lenght
                   2067:  * 
                   2068:  * Concat the given string at the end of the existing node content
1.21      daniel   2069:  */
1.23      daniel   2070: 
1.28      daniel   2071: void
                   2072: xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
1.21      daniel   2073:     if (node == NULL) return;
                   2074: 
1.23      daniel   2075:     if (node->type != XML_TEXT_NODE) {
1.21      daniel   2076:        fprintf(stderr, "xmlTextConcat: node is not text\n");
                   2077:         return;
                   2078:     }
                   2079:     node->content = xmlStrncat(node->content, content, len);
                   2080: }
                   2081: 
1.1       veillard 2082: /************************************************************************
                   2083:  *                                                                     *
1.8       veillard 2084:  *                     Output : to a FILE or in memory                 *
1.1       veillard 2085:  *                                                                     *
                   2086:  ************************************************************************/
                   2087: 
1.8       veillard 2088: static CHAR *buffer = NULL;
                   2089: static int buffer_index = 0;
                   2090: static int buffer_size = 0;
                   2091: 
1.23      daniel   2092: /**
                   2093:  * xmlBufferWriteCHAR:
                   2094:  * @string:  the string to add
                   2095:  *
                   2096:  * routine which manage and grows an output buffer. This one add
                   2097:  * CHARs at the end of the array.
                   2098:  */
1.28      daniel   2099: void
                   2100: xmlBufferWriteCHAR(const CHAR *string) {
1.8       veillard 2101:     const CHAR *cur;
                   2102: 
                   2103:     if (buffer == NULL) {
                   2104:         buffer_size = 50000;
                   2105:         buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
                   2106:        if (buffer == NULL) {
                   2107:            fprintf(stderr, "xmlBufferWrite : out of memory!\n");
                   2108:            exit(1);
                   2109:        }
                   2110:     }
                   2111:     
                   2112:     if (string == NULL) return;
                   2113:     for (cur = string;*cur != 0;cur++) {
                   2114:         if (buffer_index  + 10 >= buffer_size) {
                   2115:            buffer_size *= 2;
                   2116:            buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
                   2117:            if (buffer == NULL) {
                   2118:                fprintf(stderr, "xmlBufferWrite : out of memory!\n");
                   2119:                exit(1);
                   2120:            }
                   2121:        }
                   2122:         buffer[buffer_index++] = *cur;
                   2123:     }
                   2124:     buffer[buffer_index] = 0;
                   2125: }
                   2126: 
1.23      daniel   2127: /**
                   2128:  * xmlBufferWriteChar:
                   2129:  * @string:  the string to add
                   2130:  *
                   2131:  * routine which manage and grows an output buffer. This one add
                   2132:  * C chars at the end of the array.
                   2133:  */
1.28      daniel   2134: void
                   2135: xmlBufferWriteChar(const char *string) {
1.21      daniel   2136:     const char *cur;
1.8       veillard 2137: 
                   2138:     if (buffer == NULL) {
                   2139:         buffer_size = 50000;
                   2140:         buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
                   2141:        if (buffer == NULL) {
                   2142:            fprintf(stderr, "xmlBufferWrite : out of memory!\n");
                   2143:            exit(1);
                   2144:        }
                   2145:     }
                   2146:     
                   2147:     if (string == NULL) return;
                   2148:     for (cur = string;*cur != 0;cur++) {
                   2149:         if (buffer_index  + 10 >= buffer_size) {
                   2150:            buffer_size *= 2;
                   2151:            buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
                   2152:            if (buffer == NULL) {
                   2153:                fprintf(stderr, "xmlBufferWrite : out of memory!\n");
                   2154:                exit(1);
                   2155:            }
                   2156:        }
                   2157:         buffer[buffer_index++] = *cur;
                   2158:     }
                   2159:     buffer[buffer_index] = 0;
                   2160: }
                   2161: 
1.23      daniel   2162: /**
                   2163:  * xmlGlobalNsDump:
                   2164:  * @cur:  a namespace
                   2165:  *
                   2166:  * Dump a global Namespace, this is the old version based on PIs.
1.1       veillard 2167:  */
1.28      daniel   2168: static void
                   2169: xmlGlobalNsDump(xmlNsPtr cur) {
1.1       veillard 2170:     if (cur == NULL) {
1.19      daniel   2171:         fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
1.1       veillard 2172:        return;
                   2173:     }
1.19      daniel   2174:     if (cur->type == XML_GLOBAL_NAMESPACE) {
1.12      daniel   2175:        xmlBufferWriteChar("<?namespace");
                   2176:        if (cur->href != NULL) {
                   2177:            xmlBufferWriteChar(" href=\"");
                   2178:            xmlBufferWriteCHAR(cur->href);
                   2179:            xmlBufferWriteChar("\"");
                   2180:        }
1.16      daniel   2181:        if (cur->prefix != NULL) {
1.12      daniel   2182:            xmlBufferWriteChar(" AS=\"");
1.16      daniel   2183:            xmlBufferWriteCHAR(cur->prefix);
1.12      daniel   2184:            xmlBufferWriteChar("\"");
                   2185:        }
                   2186:        xmlBufferWriteChar("?>\n");
1.19      daniel   2187:     }
                   2188: }
                   2189: 
1.23      daniel   2190: /**
                   2191:  * xmlGlobalNsListDump:
                   2192:  * @cur:  the first namespace
                   2193:  *
                   2194:  * Dump a list of global Namespace, this is the old version based on PIs.
1.19      daniel   2195:  */
1.28      daniel   2196: static void
                   2197: xmlGlobalNsListDump(xmlNsPtr cur) {
1.19      daniel   2198:     while (cur != NULL) {
                   2199:         xmlGlobalNsDump(cur);
                   2200:        cur = cur->next;
                   2201:     }
                   2202: }
                   2203: 
1.23      daniel   2204: /**
                   2205:  * xmlNsDump:
                   2206:  * @cur:  a namespace
                   2207:  *
1.19      daniel   2208:  * Dump a local Namespace definition.
1.23      daniel   2209:  * Should be called in the context of attributes dumps.
1.19      daniel   2210:  */
1.28      daniel   2211: static void
                   2212: xmlNsDump(xmlNsPtr cur) {
1.19      daniel   2213:     if (cur == NULL) {
                   2214:         fprintf(stderr, "xmlNsDump : Ns == NULL\n");
                   2215:        return;
                   2216:     }
                   2217:     if (cur->type == XML_LOCAL_NAMESPACE) {
                   2218:         /* Within the context of an element attributes */
1.16      daniel   2219:        if (cur->prefix != NULL) {
1.19      daniel   2220:            xmlBufferWriteChar(" xmlns:");
1.16      daniel   2221:            xmlBufferWriteCHAR(cur->prefix);
1.19      daniel   2222:        } else
                   2223:            xmlBufferWriteChar(" xmlns");
                   2224:        xmlBufferWriteChar("=\"");
                   2225:        xmlBufferWriteCHAR(cur->href);
                   2226:        xmlBufferWriteChar("\"");
                   2227:     }
                   2228: }
                   2229: 
1.23      daniel   2230: /**
                   2231:  * xmlNsListDump:
                   2232:  * @cur:  the first namespace
                   2233:  *
                   2234:  * Dump a list of local Namespace definitions.
                   2235:  * Should be called in the context of attributes dumps.
1.19      daniel   2236:  */
1.28      daniel   2237: static void
                   2238: xmlNsListDump(xmlNsPtr cur) {
1.19      daniel   2239:     while (cur != NULL) {
                   2240:         xmlNsDump(cur);
                   2241:        cur = cur->next;
1.8       veillard 2242:     }
1.1       veillard 2243: }
                   2244: 
1.23      daniel   2245: /**
                   2246:  * xmlDtdDump:
                   2247:  * @doc:  the document
                   2248:  * 
                   2249:  * Dump the XML document DTD, if any.
1.17      daniel   2250:  */
1.28      daniel   2251: static void
                   2252: xmlDtdDump(xmlDocPtr doc) {
1.31      daniel   2253:     xmlDtdPtr cur = doc->intSubset;
1.21      daniel   2254: 
1.17      daniel   2255:     if (cur == NULL) {
1.31      daniel   2256:         fprintf(stderr, "xmlDtdDump : no internal subset\n");
1.17      daniel   2257:        return;
                   2258:     }
                   2259:     xmlBufferWriteChar("<!DOCTYPE ");
                   2260:     xmlBufferWriteCHAR(cur->name);
                   2261:     if (cur->ExternalID != NULL) {
                   2262:        xmlBufferWriteChar(" PUBLIC \"");
                   2263:        xmlBufferWriteCHAR(cur->ExternalID);
                   2264:        xmlBufferWriteChar("\" \"");
                   2265:        xmlBufferWriteCHAR(cur->SystemID);
                   2266:        xmlBufferWriteChar("\"");
                   2267:     }  else if (cur->SystemID != NULL) {
                   2268:        xmlBufferWriteChar(" SYSTEM \"");
                   2269:        xmlBufferWriteCHAR(cur->SystemID);
                   2270:        xmlBufferWriteChar("\"");
                   2271:     }
1.33    ! daniel   2272:     if ((cur->entities == NULL) && (cur->elements == NULL)) {
1.21      daniel   2273:        xmlBufferWriteChar(">\n");
                   2274:        return;
                   2275:     }
                   2276:     xmlBufferWriteChar(" [\n");
                   2277:     if (cur->entities != NULL)
1.18      daniel   2278:        xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1.33    ! daniel   2279:     if (cur->elements != NULL)
        !          2280:        xmlDumpElementTable((xmlElementTablePtr) cur->elements);
1.21      daniel   2281:     xmlBufferWriteChar("]");
                   2282: 
1.17      daniel   2283:     /* TODO !!! a lot more things to dump ... */
                   2284:     xmlBufferWriteChar(">\n");
                   2285: }
                   2286: 
1.23      daniel   2287: /**
                   2288:  * xmlAttrDump:
                   2289:  * @doc:  the document
                   2290:  * @cur:  the attribute pointer
                   2291:  *
                   2292:  * Dump an XML attribute
1.1       veillard 2293:  */
1.28      daniel   2294: static void
                   2295: xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
1.23      daniel   2296:     CHAR *value;
1.1       veillard 2297: 
                   2298:     if (cur == NULL) {
1.20      daniel   2299:         fprintf(stderr, "xmlAttrDump : property == NULL\n");
1.1       veillard 2300:        return;
                   2301:     }
1.8       veillard 2302:     xmlBufferWriteChar(" ");
                   2303:     xmlBufferWriteCHAR(cur->name);
1.24      daniel   2304:     value = xmlNodeListGetString(doc, cur->val, 0);
1.23      daniel   2305:     if (value) {
1.8       veillard 2306:        xmlBufferWriteChar("=\"");
1.23      daniel   2307:        xmlBufferWriteCHAR(value);
1.8       veillard 2308:        xmlBufferWriteChar("\"");
1.23      daniel   2309:        free(value);
1.3       veillard 2310:     }
1.8       veillard 2311: }
                   2312: 
1.23      daniel   2313: /**
                   2314:  * xmlAttrListDump:
                   2315:  * @doc:  the document
                   2316:  * @cur:  the first attribute pointer
                   2317:  *
                   2318:  * Dump a list of XML attributes
1.8       veillard 2319:  */
1.28      daniel   2320: static void
                   2321: xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
1.8       veillard 2322:     if (cur == NULL) {
1.20      daniel   2323:         fprintf(stderr, "xmlAttrListDump : property == NULL\n");
1.1       veillard 2324:        return;
                   2325:     }
1.8       veillard 2326:     while (cur != NULL) {
1.20      daniel   2327:         xmlAttrDump(doc, cur);
1.8       veillard 2328:        cur = cur->next;
1.1       veillard 2329:     }
                   2330: }
                   2331: 
                   2332: 
1.28      daniel   2333: static void
                   2334: xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
1.23      daniel   2335: /**
                   2336:  * xmlNodeListDump:
                   2337:  * @doc:  the document
                   2338:  * @cur:  the first node
                   2339:  * @level: the imbrication level for indenting
                   2340:  *
                   2341:  * Dump an XML node list, recursive behaviour,children are printed too.
                   2342:  */
1.28      daniel   2343: static void
                   2344: xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1.25      daniel   2345:     int needIndent = 0, i;
                   2346: 
1.1       veillard 2347:     if (cur == NULL) {
1.8       veillard 2348:         fprintf(stderr, "xmlNodeListDump : node == NULL\n");
1.1       veillard 2349:        return;
                   2350:     }
1.8       veillard 2351:     while (cur != NULL) {
1.25      daniel   2352:         if ((cur->type != XML_TEXT_NODE) &&
                   2353:            (cur->type != XML_ENTITY_REF_NODE)) {
                   2354:            if (!needIndent) {
                   2355:                needIndent = 1;
                   2356:                xmlBufferWriteChar("\n");
                   2357:            }
                   2358:        }
1.8       veillard 2359:         xmlNodeDump(doc, cur, level);
                   2360:        cur = cur->next;
1.3       veillard 2361:     }
1.25      daniel   2362:     if ((xmlIndentTreeOutput) && (needIndent))
                   2363:        for (i = 1;i < level;i++)
                   2364:            xmlBufferWriteChar("  ");
1.1       veillard 2365: }
                   2366: 
1.23      daniel   2367: /**
1.25      daniel   2368:  * xmlNodeDump:
1.23      daniel   2369:  * @doc:  the document
                   2370:  * @cur:  the current node
                   2371:  * @level: the imbrication level for indenting
                   2372:  *
                   2373:  * Dump an XML node, recursive behaviour,children are printed too.
1.1       veillard 2374:  */
1.28      daniel   2375: static void
                   2376: xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1.8       veillard 2377:     int i;
                   2378: 
1.1       veillard 2379:     if (cur == NULL) {
1.8       veillard 2380:         fprintf(stderr, "xmlNodeDump : node == NULL\n");
                   2381:        return;
                   2382:     }
1.23      daniel   2383:     if (cur->type == XML_TEXT_NODE) {
1.8       veillard 2384:        if (cur->content != NULL)
                   2385:            xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1.14      daniel   2386:        return;
                   2387:     }
1.23      daniel   2388:     if (cur->type == XML_COMMENT_NODE) {
1.14      daniel   2389:        if (cur->content != NULL) {
                   2390:            xmlBufferWriteChar("<!--");
1.18      daniel   2391:            xmlBufferWriteCHAR(cur->content);
1.14      daniel   2392:            xmlBufferWriteChar("-->");
                   2393:        }
1.8       veillard 2394:        return;
                   2395:     }
1.23      daniel   2396:     if (cur->type == XML_ENTITY_REF_NODE) {
                   2397:         xmlBufferWriteChar("&");
                   2398:        xmlBufferWriteCHAR(cur->name);
                   2399:         xmlBufferWriteChar(";");
                   2400:        return;
                   2401:     }
1.21      daniel   2402:     if (xmlIndentTreeOutput)
                   2403:        for (i = 0;i < level;i++)
                   2404:            xmlBufferWriteChar("  ");
1.8       veillard 2405: 
                   2406:     xmlBufferWriteChar("<");
1.16      daniel   2407:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
                   2408:         xmlBufferWriteCHAR(cur->ns->prefix);
1.8       veillard 2409:        xmlBufferWriteChar(":");
                   2410:     }
                   2411: 
                   2412:     xmlBufferWriteCHAR(cur->name);
1.19      daniel   2413:     if (cur->nsDef)
                   2414:         xmlNsListDump(cur->nsDef);
1.8       veillard 2415:     if (cur->properties != NULL)
1.20      daniel   2416:         xmlAttrListDump(doc, cur->properties);
1.8       veillard 2417: 
                   2418:     if ((cur->content == NULL) && (cur->childs == NULL)) {
                   2419:         xmlBufferWriteChar("/>\n");
1.1       veillard 2420:        return;
                   2421:     }
1.8       veillard 2422:     xmlBufferWriteChar(">");
                   2423:     if (cur->content != NULL)
                   2424:        xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
                   2425:     if (cur->childs != NULL) {
                   2426:        xmlNodeListDump(doc, cur->childs, level + 1);
                   2427:     }
                   2428:     xmlBufferWriteChar("</");
1.16      daniel   2429:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
                   2430:         xmlBufferWriteCHAR(cur->ns->prefix);
1.8       veillard 2431:        xmlBufferWriteChar(":");
1.1       veillard 2432:     }
1.8       veillard 2433: 
                   2434:     xmlBufferWriteCHAR(cur->name);
                   2435:     xmlBufferWriteChar(">\n");
1.1       veillard 2436: }
                   2437: 
1.23      daniel   2438: /**
                   2439:  * xmlDocContentDump:
                   2440:  * @cur:  the document
                   2441:  *
                   2442:  * Dump an XML document.
1.1       veillard 2443:  */
1.28      daniel   2444: static void
                   2445: xmlDocContentDump(xmlDocPtr cur) {
1.12      daniel   2446:     if (oldXMLWDcompatibility)
                   2447:        xmlBufferWriteChar("<?XML version=\"");
                   2448:     else 
                   2449:        xmlBufferWriteChar("<?xml version=\"");
1.8       veillard 2450:     xmlBufferWriteCHAR(cur->version);
1.15      daniel   2451:     xmlBufferWriteChar("\"");
                   2452:     if (cur->encoding != NULL) {
                   2453:         xmlBufferWriteChar(" encoding=\"");
                   2454:        xmlBufferWriteCHAR(cur->encoding);
                   2455:        xmlBufferWriteChar("\"");
                   2456:     }
                   2457:     switch (cur->standalone) {
                   2458:         case 0:
                   2459:            xmlBufferWriteChar(" standalone=\"no\"");
                   2460:            break;
                   2461:         case 1:
                   2462:            xmlBufferWriteChar(" standalone=\"yes\"");
                   2463:            break;
                   2464:     }
                   2465:     xmlBufferWriteChar("?>\n");
1.31      daniel   2466:     if (cur->intSubset != NULL)
1.21      daniel   2467:         xmlDtdDump(cur);
1.19      daniel   2468:     if (cur->root != NULL) {
                   2469:        /* global namespace definitions, the old way */
                   2470:        if (oldXMLWDcompatibility)
                   2471:            xmlGlobalNsListDump(cur->oldNs);
                   2472:        else 
                   2473:            xmlUpgradeOldNs(cur);
1.8       veillard 2474:         xmlNodeDump(cur, cur->root, 0);
1.19      daniel   2475:     }
                   2476: }
                   2477: 
1.23      daniel   2478: /**
                   2479:  * xmlDocDumpMemory:
                   2480:  * @cur:  the document
                   2481:  * @mem:  OUT: the memory pointer
                   2482:  * @size:  OUT: the memory lenght
                   2483:  *
                   2484:  * Dump an XML document in memory and return the CHAR * and it's size.
                   2485:  * It's up to the caller to free the memory.
1.19      daniel   2486:  */
1.28      daniel   2487: void
                   2488: xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
1.19      daniel   2489:     if (cur == NULL) {
1.31      daniel   2490: #ifdef DEBUG_TREE
                   2491:         fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
                   2492: #endif
1.19      daniel   2493:        *mem = NULL;
                   2494:        *size = 0;
                   2495:        return;
                   2496:     }
                   2497:     buffer_index = 0;
                   2498:     xmlDocContentDump(cur);
1.8       veillard 2499: 
                   2500:     *mem = buffer;
                   2501:     *size = buffer_index;
1.1       veillard 2502: }
                   2503: 
1.23      daniel   2504: /**
                   2505:  * xmlGetDocCompressMode:
                   2506:  * @doc:  the document
                   2507:  *
                   2508:  * get the compression ratio for a document, ZLIB based
                   2509:  * return values: 0 (uncompressed) to 9 (max compression)
                   2510:  */
1.28      daniel   2511: int
                   2512:  xmlGetDocCompressMode (xmlDocPtr doc) {
1.23      daniel   2513:     if (doc == NULL) return(-1);
                   2514:     return(doc->compression);
                   2515: }
                   2516: 
                   2517: /**
                   2518:  * xmlSetDocCompressMode:
                   2519:  * @doc:  the document
                   2520:  * @mode:  the compression ratio
                   2521:  *
                   2522:  * set the compression ratio for a document, ZLIB based
                   2523:  * Correct values: 0 (uncompressed) to 9 (max compression)
                   2524:  */
1.28      daniel   2525: void
                   2526: xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
1.23      daniel   2527:     if (doc == NULL) return;
                   2528:     if (mode < 0) doc->compression = 0;
                   2529:     else if (mode > 9) doc->compression = 9;
                   2530:     else doc->compression = mode;
                   2531: }
                   2532: 
                   2533: /**
                   2534:  * xmlGetCompressMode:
                   2535:  *
                   2536:  * get the default compression mode used, ZLIB based.
                   2537:  * return values: 0 (uncompressed) to 9 (max compression)
                   2538:  */
1.28      daniel   2539: int
                   2540:  xmlGetCompressMode(void) {
1.23      daniel   2541:     return(xmlCompressMode);
                   2542: }
                   2543: 
                   2544: /**
                   2545:  * xmlSetCompressMode:
                   2546:  * @mode:  the compression ratio
                   2547:  *
                   2548:  * set the default compression mode used, ZLIB based
                   2549:  * Correct values: 0 (uncompressed) to 9 (max compression)
1.1       veillard 2550:  */
1.28      daniel   2551: void
                   2552: xmlSetCompressMode(int mode) {
1.23      daniel   2553:     if (mode < 0) xmlCompressMode = 0;
                   2554:     else if (mode > 9) xmlCompressMode = 9;
                   2555:     else xmlCompressMode = mode;
                   2556: }
1.1       veillard 2557: 
1.23      daniel   2558: /**
                   2559:  * xmlDocDump:
                   2560:  * @f:  the FILE*
                   2561:  * @cur:  the document
                   2562:  *
                   2563:  * Dump an XML document to an open FILE.
                   2564:  */
1.28      daniel   2565: void
                   2566: xmlDocDump(FILE *f, xmlDocPtr cur) {
1.1       veillard 2567:     if (cur == NULL) {
1.31      daniel   2568: #ifdef DEBUG_TREE
1.1       veillard 2569:         fprintf(stderr, "xmlDocDump : document == NULL\n");
1.31      daniel   2570: #endif
1.1       veillard 2571:        return;
                   2572:     }
1.8       veillard 2573:     buffer_index = 0;
1.19      daniel   2574:     xmlDocContentDump(cur);
1.8       veillard 2575: 
                   2576:     fwrite(buffer, sizeof(CHAR), buffer_index, f);
1.23      daniel   2577: }
                   2578: 
                   2579: /**
                   2580:  * xmlSaveFile:
                   2581:  * @filename:  the filename
                   2582:  * @cur:  the document
                   2583:  *
                   2584:  * Dump an XML document to a file. Will use compression if
                   2585:  * compiled in and enabled.
                   2586:  * returns: the number of file written or -1 in case of failure.
                   2587:  */
1.28      daniel   2588: int
                   2589: xmlSaveFile(const char *filename, xmlDocPtr cur) {
1.23      daniel   2590: #ifdef HAVE_ZLIB_H
                   2591:     gzFile zoutput = NULL;
                   2592:     char mode[15];
                   2593: #endif
1.24      daniel   2594:     FILE *output = NULL;
1.23      daniel   2595:     int ret;
                   2596: 
                   2597: #ifdef HAVE_ZLIB_H
                   2598:     if ((cur->compression > 0) && (cur->compression <= 9)) {
                   2599:         sprintf(mode, "w%d", cur->compression);
                   2600:        zoutput = gzopen(filename, mode);
                   2601:     }
                   2602:     if (zoutput == NULL) {
                   2603: #endif
                   2604:         output = fopen(filename, "w");
                   2605:        if (output == NULL) return(-1);
                   2606: #ifdef HAVE_ZLIB_H
                   2607:     }
                   2608: #endif
                   2609: 
                   2610:     /* 
                   2611:      * save the content to a temp buffer.
                   2612:      */
                   2613:     buffer_index = 0;
                   2614:     xmlDocContentDump(cur);
                   2615: 
                   2616: #ifdef HAVE_ZLIB_H
                   2617:     if (zoutput != NULL) {
                   2618:         ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
                   2619:        gzclose(zoutput);
                   2620:        return(ret);
                   2621:     }
                   2622: #endif
                   2623:     ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
                   2624:     fclose(output);
                   2625:     return(ret * sizeof(CHAR));
1.1       veillard 2626: }
                   2627: 

Webmaster