Changeset 71 for trunk/src/helpers/xml.c
- Timestamp:
- May 22, 2001, 7:18:41 PM (24 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/helpers/xml.c
r65 r71 7 7 * layers: 8 8 * 9 * -- The bottom layer is implemented by @expat, which I have10 * 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. 11 11 * 12 12 * See xmlparse.c for an introduction. … … 16 16 * which is vaguely modelled after the Document Object Model 17 17 * (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. 18 26 * 19 27 * <B>XML</B> … … 43 51 * Most notably, there are the following differences: 44 52 * 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 * 45 57 * -- Not all node types are implemented. See _DOMNODE for 46 58 * the supported types. 47 59 * 48 * -- Only a s mall subset of the standardized methods is implemented,60 * -- Only a subset of the standardized methods is implemented, 49 61 * and they are called differently to adhere to the xwphelpers 50 62 * conventions. … … 349 361 * associated with its members. 350 362 * 351 * NOTE: If you call this for derived types, call352 * this LAST, after you have cleared additional353 * members. After calling this, pNode is no longer354 * 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. 355 367 * 356 368 *@@added V0.9.9 (2001-02-16) [umoeller] … … 383 395 { 384 396 // call delete recursively 397 PDOMNODE pNext = (PDOMNODE)treeNext((TREE*)pAttrib); 385 398 xmlDeleteNode((PNODEBASE)pAttrib); 386 399 // 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; 390 402 } 391 403 break; } … … 395 407 case DOMNODE_PROCESSING_INSTRUCTION: 396 408 case DOMNODE_COMMENT: 409 pDomNode = (PDOMNODE)pNode; 410 break; 411 397 412 case DOMNODE_DOCUMENT: 413 if (((PDOMDOCUMENTNODE)pNode)->pDocType) 414 xmlDeleteNode((PNODEBASE)((PDOMDOCUMENTNODE)pNode)->pDocType); 398 415 pDomNode = (PDOMNODE)pNode; 399 416 break; … … 441 458 pParticle = (PCMELEMENTPARTICLE)pDelNode->pItemData; 442 459 xmlDeleteNode((PNODEBASE)pParticle); 443 // treeDelete(pp-> ###460 // treeDelete(pp-> // @@todo 444 461 pDelNode = pDelNode->pNext; 445 462 } … … 962 979 * _XMLCONTENT content model (which is the @expat structure). 963 980 * 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. 964 986 * 965 987 *@@added V0.9.9 (2001-02-16) [umoeller] … … 2120 2142 /* ****************************************************************** 2121 2143 * 2122 * DOM rootAPIs2144 * DOM parser APIs 2123 2145 * 2124 2146 ********************************************************************/ … … 2158 2180 + TRUE); // if last, this will clean up the parser 2159 2181 * 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. 2162 2194 * 2163 2195 *@@added V0.9.9 (2001-02-14) [umoeller] … … 2183 2215 // create the document node 2184 2216 arc = xmlCreateDomNode(NULL, // no parent 2185 DOMNODE_DOCUMENT,2186 NULL,2187 0,2188 &pDocument);2217 DOMNODE_DOCUMENT, 2218 NULL, 2219 0, 2220 &pDocument); 2189 2221 2190 2222 if (arc == NO_ERROR) … … 2263 2295 /* 2264 2296 *@@ xmlParse: 2265 * parses another pieceof XML data.2297 * parses another chunk of XML data. 2266 2298 * 2267 2299 * If (fIsLast == TRUE), the internal @expat parser … … 2375 2407 pDom->pParser = NULL; 2376 2408 } 2409 2410 xmlDeleteNode((PNODEBASE)pDom->pDocumentNode); 2377 2411 2378 2412 free(pDom); … … 2645 2679 return (NULL); 2646 2680 } 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 2713 APIRET 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 2750 VOID 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 2919 APIRET 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.