Changeset 71 for trunk/src/helpers/xml.c


Ignore:
Timestamp:
May 22, 2001, 7:18:41 PM (24 years ago)
Author:
umoeller
Message:

misc updates

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/xml.c

    r65 r71  
    77 *      layers:
    88 *
    9  *      --  The bottom layer is implemented by @expat, which I have
    10  *          ported and hacked to the xwphelpers.
     9 *      --  The bottom layer is implemented by the @expat parser,
     10 *          which I have ported and hacked to the xwphelpers.
    1111 *
    1212 *          See xmlparse.c for an introduction.
     
    1616 *          which is vaguely modelled after the Document Object Model
    1717 *          (DOM) standardized by the W3C. That's this file.
     18 *
     19 *          This top layer allows you to do two things VERY EASILY:
     20 *
     21 *          1)  Parse an XML document (which uses expat internally)
     22 *              and build a DOM tree from that. See xmlCreateDOM.
     23 *
     24 *          2)  Create a DOM tree in memory and write an XML
     25 *              document from that. See xmlCreateDocument.
    1826 *
    1927 *      <B>XML</B>
     
    4351 *      Most notably, there are the following differences:
    4452 *
     53 *      --  External entities don't work yet. As a result, DOCTYPE's
     54 *          only make sense if the entire DTD is in the same document
     55 *          (internal subset).
     56 *
    4557 *      --  Not all node types are implemented. See _DOMNODE for
    4658 *          the supported types.
    4759 *
    48  *      --  Only a small subset of the standardized methods is implemented,
     60 *      --  Only a subset of the standardized methods is implemented,
    4961 *          and they are called differently to adhere to the xwphelpers
    5062 *          conventions.
     
    349361 *      associated with its members.
    350362 *
    351  *      NOTE: If you call this for derived types, call
    352  *      this LAST, after you have cleared additional
    353  *      members. After calling this, pNode is no longer
    354  *      valid.
     363 *      After calling this, pNode is no longer valid.
     364 *
     365 *      If you invoke this on a DOCUMENT node, the
     366 *      entire DOM tree will get deleted recursively.
    355367 *
    356368 *@@added V0.9.9 (2001-02-16) [umoeller]
     
    383395                {
    384396                    // call delete recursively
     397                    PDOMNODE pNext = (PDOMNODE)treeNext((TREE*)pAttrib);
    385398                    xmlDeleteNode((PNODEBASE)pAttrib);
    386399                            // this will remove pAttrib from pNode's attrib
    387                             // tree and rebalance the tree; treeNext will
    388                             // still work #### noooooo
    389                     pAttrib = (PDOMNODE)treeNext((TREE*)pAttrib);
     400                            // tree and rebalance the tree
     401                    pAttrib = pNext;
    390402                }
    391403            break; }
     
    395407            case DOMNODE_PROCESSING_INSTRUCTION:
    396408            case DOMNODE_COMMENT:
     409                pDomNode = (PDOMNODE)pNode;
     410            break;
     411
    397412            case DOMNODE_DOCUMENT:
     413                if (((PDOMDOCUMENTNODE)pNode)->pDocType)
     414                    xmlDeleteNode((PNODEBASE)((PDOMDOCUMENTNODE)pNode)->pDocType);
    398415                pDomNode = (PDOMNODE)pNode;
    399416            break;
     
    441458                                pParticle = (PCMELEMENTPARTICLE)pDelNode->pItemData;
    442459                        xmlDeleteNode((PNODEBASE)pParticle);
    443                         //  treeDelete(pp->         ###
     460                        //  treeDelete(pp->         // @@todo
    444461                        pDelNode = pDelNode->pNext;
    445462                    }
     
    962979 *      _XMLCONTENT content model (which is the @expat structure).
    963980 *      This recurses, if necessary.
     981 *
     982 *      NOTE: As opposed to the other "create" functions,
     983 *      this does not take a parent node as input. If this
     984 *      returns NO_ERROR, it is the caller's responsibility
     985 *      to add the produced node to the document's DOCTYPE node.
    964986 *
    965987 *@@added V0.9.9 (2001-02-16) [umoeller]
     
    21202142/* ******************************************************************
    21212143 *
    2122  *   DOM root APIs
     2144 *   DOM parser APIs
    21232145 *
    21242146 ********************************************************************/
     
    21582180 +                         TRUE); // if last, this will clean up the parser
    21592181 *
    2160  *      3) Process the data in the DOM tree. When done,
    2161  *         call xmlFreeDOM, which will free all memory.
     2182 *      3) Process the data in the DOM tree.
     2183 *
     2184 *         Look at the DOMNODE definition to see how you
     2185 *         can traverse the data. Essentially, everything
     2186 *         is based on linked lists and string maps.
     2187 *
     2188 *         A few helper functions have been added for
     2189 *         quick lookup. See xmlGetRootElement,
     2190 *         xmlGetFirstChild, xmlGetLastChild, xmlGetFirstText,
     2191 *         xmlGetElementsByTagName, xmlGetAttribute.
     2192 *
     2193 *      4) When done, call xmlFreeDOM, which will free all memory.
    21622194 *
    21632195 *@@added V0.9.9 (2001-02-14) [umoeller]
     
    21832215        // create the document node
    21842216        arc = xmlCreateDomNode(NULL, // no parent
    2185                             DOMNODE_DOCUMENT,
    2186                             NULL,
    2187                             0,
    2188                             &pDocument);
     2217                               DOMNODE_DOCUMENT,
     2218                               NULL,
     2219                               0,
     2220                               &pDocument);
    21892221
    21902222        if (arc == NO_ERROR)
     
    22632295/*
    22642296 *@@ xmlParse:
    2265  *      parses another piece of XML data.
     2297 *      parses another chunk of XML data.
    22662298 *
    22672299 *      If (fIsLast == TRUE), the internal @expat parser
     
    23752407            pDom->pParser = NULL;
    23762408        }
     2409
     2410        xmlDeleteNode((PNODEBASE)pDom->pDocumentNode);
    23772411
    23782412        free(pDom);
     
    26452679    return (NULL);
    26462680}
     2681
     2682/* ******************************************************************
     2683 *
     2684 *   DOM build
     2685 *
     2686 ********************************************************************/
     2687
     2688/*
     2689 *@@ xmlCreateDocument:
     2690 *      creates a new XML document.
     2691 *
     2692 *      This is the first step in creating a DOM
     2693 *      tree in memory.
     2694 *
     2695 *      This function creates a DOCUMENT node
     2696 *      (which is returned) and a root ELEMENT node
     2697 *      within the document. For convenience, the
     2698 *      root ELEMENT node is returned as well.
     2699 *
     2700 *      This does not create a DOCTYPE node in
     2701 *      the document.
     2702 *
     2703 *      After this, you can add sub-elements and
     2704 *      attributes to the root element using
     2705 *      xmlCreateElementNode and xmlCreateAttributeNode.
     2706 *
     2707 *      Use xmlDeleteNode on the DOCUMENT node
     2708 *      to delete the entire DOM tree.
     2709 *
     2710 *@@added V0.9.12 (2001-05-21) [umoeller]
     2711 */
     2712
     2713APIRET xmlCreateDocument(const char *pcszRootElementName,   // in: root element name
     2714                         PDOMDOCUMENTNODE *ppDocument,      // out: DOCUMENT node
     2715                         PDOMNODE *ppRootElement)           // out: root ELEMENT node within DOCUMENT
     2716{
     2717    APIRET arc = NO_ERROR;
     2718    PDOMDOCUMENTNODE pDocument = NULL;
     2719    PDOMNODE pRootElement = NULL;
     2720
     2721    if ( (!pcszRootElementName) || (!ppDocument) || (!ppRootElement) )
     2722        arc = ERROR_INVALID_PARAMETER;
     2723    else
     2724        // create the document node
     2725        if (!(arc = xmlCreateDomNode(NULL, // no parent
     2726                                     DOMNODE_DOCUMENT,
     2727                                     NULL,
     2728                                     0,
     2729                                     (PDOMNODE*)&pDocument)))
     2730            if (!(arc = xmlCreateDomNode((PDOMNODE)pDocument,     // parent
     2731                                         DOMNODE_ELEMENT,
     2732                                         pcszRootElementName,
     2733                                         0,
     2734                                         &pRootElement)))
     2735            {
     2736                *ppDocument = pDocument;
     2737                *ppRootElement = pRootElement;
     2738            }
     2739
     2740    return (arc);
     2741}
     2742
     2743/*
     2744 *@@ WriteNodes:
     2745 *      internal helper for writing out the nodes.
     2746 *
     2747 *@@added V0.9.12 (2001-05-21) [umoeller]
     2748 */
     2749
     2750VOID WriteNodes(PXSTRING pxstr,
     2751                PDOMNODE pDomNode)       // in: node whose children are to be written (initially DOCUMENT)
     2752{
     2753    PLISTNODE pListNode;
     2754
     2755    BOOL fMixedContent = (xmlGetFirstText(pDomNode) != NULL);
     2756
     2757    for (pListNode = lstQueryFirstNode(&pDomNode->llChildren);
     2758         (pListNode);
     2759         pListNode = pListNode->pNext)
     2760    {
     2761        PDOMNODE pChildNode = (PDOMNODE)pListNode->pItemData;
     2762
     2763        switch (pChildNode->NodeBase.ulNodeType)
     2764        {
     2765            case DOMNODE_ELEMENT:
     2766            {
     2767                PDOMNODE pAttribNode;
     2768                // write out opening ELEMENT tag
     2769                // add a line break if this does NOT have mixed
     2770                // content
     2771                if (!fMixedContent)
     2772                    xstrcatc(pxstr, '\n');
     2773
     2774                xstrcatc(pxstr, '<');
     2775                xstrcats(pxstr, &pChildNode->NodeBase.strNodeName);
     2776
     2777                // go through attributes
     2778                for (pAttribNode = (PDOMNODE)treeFirst(pChildNode->AttributesMap);
     2779                     (pAttribNode);
     2780                     pAttribNode = (PDOMNODE)treeNext((TREE*)pAttribNode))
     2781                {
     2782                    xstrcat(pxstr, "\n    ", 0);
     2783                    xstrcats(pxstr, &pAttribNode->NodeBase.strNodeName);
     2784                    xstrcat(pxstr, "=\"", 0);
     2785                    xstrcats(pxstr, pAttribNode->pstrNodeValue);
     2786                    xstrcatc(pxstr, '\"');
     2787                }
     2788
     2789                // now check... do we have child nodes?
     2790                if (lstCountItems(&pChildNode->llChildren))
     2791                {
     2792                    // yes:
     2793                    xstrcatc(pxstr, '>');
     2794
     2795                    // recurse into this child element
     2796                    WriteNodes(pxstr, pChildNode);
     2797
     2798                    if (!fMixedContent)
     2799                        xstrcatc(pxstr, '\n');
     2800
     2801                    // write closing tag
     2802                    xstrcat(pxstr, "</", 0);
     2803                    xstrcats(pxstr, &pChildNode->NodeBase.strNodeName);
     2804                    xstrcatc(pxstr, '>');
     2805                }
     2806                else
     2807                {
     2808                    // no child nodes:
     2809                    // mark this tag as "empty"
     2810                    xstrcat(pxstr, "/>", 0);
     2811                }
     2812            }
     2813            break;
     2814
     2815            case DOMNODE_TEXT:
     2816            case DOMNODE_COMMENT:
     2817                // that's simple
     2818                xstrcats(pxstr, pChildNode->pstrNodeValue);
     2819            break;
     2820
     2821            case DOMNODE_DOCUMENT_TYPE:
     2822                // @@todo
     2823            break;
     2824
     2825        }
     2826    }
     2827}
     2828
     2829/*
     2830 *@@ xmlWriteDocument:
     2831 *      creates a complete XML document in the specified
     2832 *      string buffer from the specified DOMDOCUMENTNODE.
     2833 *
     2834 *      This creates a full XML document, starting with
     2835 *      the <?xml...?> header, the DTD (if present),
     2836 *      and the elements and attributes.
     2837 *
     2838 *      The input XSTRING must be initialized. Its
     2839 *      contents will be overwritten, if any exists.
     2840 *
     2841 *      Sooo... to write a full XML document to disk,
     2842 *      do the following:
     2843 *
     2844 *      1)  Call xmlCreateDocument to have an empty
     2845 *          document with a root element created.
     2846 *
     2847 *      2)  Add elements, subelements, and attributes
     2848 *          using xmlCreateElementNode and
     2849 *          xmlCreateAttributeNode.
     2850 *
     2851 *      3)  Call xmlWriteDocument to have the XML
     2852 *          document written into an XSTRING.
     2853 *
     2854 *      4)  Write the XSTRING to disk, e.g. using
     2855 *          fwrite().
     2856 *
     2857 *          Note: You can also use doshWriteTextFile,
     2858 *          but you should then first convert the
     2859 *          line format using xstrConvertLineFormat.
     2860 *
     2861 *      Example:
     2862 *
     2863 +          APIRET arc = NO_ERROR;
     2864 +          PDOMDOCUMENTNODE pDocument = NULL;
     2865 +          PDOMNODE pRootElement = NULL;
     2866 +
     2867 +          // create a DOM
     2868 +          if (!(arc = xmlCreateDocument("MYROOTNODE",
     2869 +                                        &pDocument,
     2870 +                                        &pRootElement)))
     2871 +          {
     2872 +              // add subelements to the root element
     2873 +              PDOMNODE pSubelement;
     2874 +              if (!(arc = xmlCreateElementNode(pRootElement,
     2875 +                                               "MYSUBELEMENT",
     2876 +                                               &pSubelement)))
     2877 +              {
     2878 +                  // add an attribute
     2879 +                  PDOMNODE pAttribute;
     2880 +                  if (!(arc = xmlCreateAttributeNode(pSubElement,
     2881 +                                                     "MYATTRIB",
     2882 +                                                     "VALUE",
     2883 +                                                     &pAttribute)))
     2884 +                  {
     2885 +                      // alright, turn this into a string
     2886 +                      XSTRING str;
     2887 +                      xstrInit(&str, 1000);
     2888 +                      if (!(arc = xmlWriteDocument(pDocument,
     2889 +                                                   "ISO-8859-1",
     2890 +                                                   NULL,      // or DOCTYPE
     2891 +                                                   &str)))
     2892 +                      {
     2893 +                          FILE *file = fopen("myfile.xml", "w");
     2894 +                          fwrite(str.psz,
     2895 +                                 1,
     2896 +                                 str.ulLength,
     2897 +                                 file);
     2898 +                          fclose(file);
     2899 +                      }
     2900 +                  }
     2901 +              }
     2902 +
     2903 +              // this kills the entire tree
     2904 +              xmlDeleteNode((PNODEBASE)pDocument);
     2905 +
     2906 +          }
     2907 +
     2908 *
     2909 *      A note about whitespace handling. Presently, this
     2910 *      adds line breaks after the opening tag of an
     2911 *      element if the element has element content only.
     2912 *      However, if the element has mixed content, this
     2913 *      line break is NOT automatically added because
     2914 *      white space may then be significant.
     2915 *
     2916 *@@added V0.9.12 (2001-05-21) [umoeller]
     2917 */
     2918
     2919APIRET xmlWriteDocument(PDOMDOCUMENTNODE pDocument,     // in: document node
     2920                        const char *pcszEncoding,       // in: encoding string (e.g. "ISO-8859-1")
     2921                        const char *pcszDoctype,        // in: entire DOCTYPE statement or NULL
     2922                        PXSTRING pxstr)                 // out: document
     2923{
     2924    APIRET arc = NO_ERROR;
     2925
     2926    if ( (!pDocument) || (!pcszEncoding) || (!pxstr) )
     2927        arc = ERROR_INVALID_PARAMETER;
     2928    else
     2929    {
     2930        // <?xml version="1.0" encoding="ISO-8859-1"?>
     2931        xstrcpy(pxstr, "<?xml version=\"1.0\" encoding=\"", 0);
     2932        xstrcat(pxstr, pcszEncoding, 0);
     2933        xstrcat(pxstr, "\"?>\n", 0);
     2934
     2935        // write entire DOCTYPE statement
     2936        if (pcszDoctype)
     2937        {
     2938            xstrcatc(pxstr, '\n');
     2939            xstrcat(pxstr, pcszDoctype, 0);
     2940            xstrcatc(pxstr, '\n');
     2941        }
     2942
     2943        // write out children
     2944        WriteNodes(pxstr, (PDOMNODE)pDocument);
     2945
     2946        xstrcatc(pxstr, '\n');
     2947    }
     2948
     2949    return (arc);
     2950}
     2951
     2952
Note: See TracChangeset for help on using the changeset viewer.