/* * This is a program to test the concept of an XML Streamer. * Ref: http://blogs.msdn.com/mfussell/archive/2005/02/12/371546.aspx */ #include #include #include #include #include #undef DEBUG static const xmlChar *build_qname(const char *prefix,const char *name) { static xmlChar *buf=0; static int buflen=0; int len; if (!prefix) { if (!name && buf) { g_free((char *)buf); buf=NULL; buflen=0; } return BAD_CAST name; } else { len=strlen(prefix)+strlen(name)+2; if (buflenlen;i++) g_tree_remove(namespaces, g_ptr_array_index(array,i)); g_ptr_array_free(array,TRUE); } xmlTextWriterEndElement(dst); } else elements=g_slist_prepend(elements,array); return elements; } int stream(xmlTextWriter *dst,xmlTextReader *src) { int i,r,type; GTree *namespaces; /* key: URI, value: prefix */ GSList *elements=NULL; /* Tail is root, Head is current element */ GPtrArray *array; /* Array of keys */ const char *uri,*prefix; gboolean doc_started=FALSE; xmlNode *node; xmlDtd *dtd; xmlBuffer *buf; namespaces=g_tree_new((GCompareFunc)strcmp); g_tree_insert(namespaces,"http://www.w3.org/XML/1998/namespace","xml"); g_tree_insert(namespaces,"http://www.w3.org/2000/xmlns/","xmlns"); xmlTextReaderSetParserProp(src,XML_PARSER_LOADDTD,0); xmlTextReaderSetParserProp(src,XML_PARSER_DEFAULTATTRS,0); xmlTextReaderSetParserProp(src,XML_PARSER_VALIDATE,0); xmlTextReaderSetParserProp(src,XML_PARSER_SUBST_ENTITIES,0); while ((r=xmlTextReaderRead(src))==1) { type=xmlTextReaderNodeType(src); if (!doc_started && type==XML_READER_TYPE_ELEMENT || type==XML_READER_TYPE_DOCUMENT || type==XML_READER_TYPE_DOCUMENT_TYPE) { i=xmlTextReaderStandalone(src); xmlTextWriterStartDocument(dst, xmlTextReaderConstXmlVersion(src), xmlTextReaderConstEncoding(src), i>0?"yes":i==0?"no":NULL); doc_started=TRUE; } #ifdef DEBUG fprintf(stderr,"*** Node type %d\n",type); #endif switch(type) { case XML_READER_TYPE_ELEMENT: elements=stream_element(dst,src,namespaces,elements); break; case XML_READER_TYPE_TEXT: case XML_READER_TYPE_WHITESPACE: case XML_READER_TYPE_SIGNIFICANT_WHITESPACE: xmlTextWriterWriteString(dst,xmlTextReaderConstValue(src)); break; case XML_READER_TYPE_CDATA: xmlTextWriterWriteCDATA(dst,xmlTextReaderConstValue(src)); break; case XML_READER_TYPE_ENTITY_REFERENCE: xmlTextWriterWriteFormatRaw(dst,"&%s;", xmlTextReaderConstName(src)); break; case XML_READER_TYPE_XML_DECLARATION: /* Not generated by libxml version 2.6.27 */ break; case XML_READER_TYPE_PROCESSING_INSTRUCTION: xmlTextWriterWritePI(dst,xmlTextReaderConstName(src), xmlTextReaderConstValue(src)); break; case XML_READER_TYPE_DOCUMENT_TYPE: node=xmlTextReaderCurrentNode(src); if (node->type!=XML_DTD_NODE) xmlTextWriterWriteDTD(dst,xmlTextReaderConstName(src), NULL,NULL,NULL); else { dtd=(xmlDtd *)node; buf=xmlBufferCreate(); if (dtd->entities) xmlDumpEntitiesTable(buf, (xmlEntitiesTable *)dtd->entities); if (dtd->pentities) xmlDumpEntitiesTable(buf, (xmlEntitiesTable *)dtd->pentities); /* This is not quite right in that it expands entities, * but I don't know how to do better. */ if (dtd->elements) xmlDumpElementTable(buf, (xmlElementTable *)dtd->elements); if (dtd->attributes) xmlDumpAttributeTable(buf, (xmlAttributeTable *)dtd->attributes); if (dtd->notations) xmlDumpNotationTable(buf, (xmlNotationTable *)dtd->notations); xmlTextWriterWriteDTD(dst,dtd->name,dtd->ExternalID, dtd->SystemID,*buf->content?buf->content:NULL); xmlBufferFree(buf); } break; case XML_READER_TYPE_COMMENT: xmlTextWriterWriteComment(dst,xmlTextReaderConstValue(src)); break; case XML_READER_TYPE_END_ELEMENT: array=elements->data; elements=g_slist_remove_link(elements,elements); if (array) { for(i=0;ilen;i++) g_tree_remove(namespaces,g_ptr_array_index(array,i)); g_ptr_array_free(array,TRUE); } xmlTextWriterEndElement(dst); break; case XML_READER_TYPE_NONE: case XML_READER_TYPE_ATTRIBUTE: case XML_READER_TYPE_ENTITY: case XML_READER_TYPE_DOCUMENT: case XML_READER_TYPE_DOCUMENT_FRAGMENT: case XML_READER_TYPE_NOTATION: case XML_READER_TYPE_END_ENTITY: break; } } if (doc_started) xmlTextWriterEndDocument(dst); return r; } main() { int r; xmlTextWriter *dst; xmlTextReader *src; src=xmlReaderForFd(0,NULL,NULL,XML_PARSE_NONET); dst=xmlNewTextWriterFilename("/dev/stdout",0); r=stream(dst,src); xmlFreeTextReader(src); xmlFreeTextWriter(dst); exit(r); }