static void writeAttributes(Serialization *serialization, DFNode *element) { // Sort the keys by their tag, to ensure that we always write attributes out in the same order. // This is important for automated tests which rely on consistent output for a given XML tree. DFAttribute *attrs = (DFAttribute *)xmalloc(element->attrsCount*sizeof(DFAttribute)); memcpy(attrs,element->attrs,element->attrsCount*sizeof(DFAttribute)); qsort(attrs,element->attrsCount,sizeof(DFAttribute),compareAttrs); for (unsigned int i = 0; i < element->attrsCount; i++) { Tag tag = attrs[i].tag; const TagDecl *tagDecl = DFNameMapNameForTag(serialization->doc->map,tag); assert(tagDecl != NULL); const NamespaceDecl *nsDecl = DFNameMapNamespaceForID(serialization->doc->map,tagDecl->namespaceID); assert(nsDecl != NULL); const xmlChar *prefix = (const xmlChar *)nsDecl->prefix; const xmlChar *localName = (const xmlChar *)tagDecl->localName; const xmlChar *value = (const xmlChar *)attrs[i].value; if (serialization->html && (tagDecl->namespaceID == NAMESPACE_HTML)) xmlTextWriterWriteAttribute(serialization->writer,localName,value); else xmlTextWriterWriteAttributeNS(serialization->writer,prefix,localName,NULL,value); } free(attrs); }
static void writeElement(Serialization *serialization, DFNode *element, int depth) { const TagDecl *tagDecl = DFNameMapNameForTag(serialization->doc->map,element->tag); assert(tagDecl != NULL); const NamespaceDecl *nsDecl = DFNameMapNamespaceForID(serialization->doc->map,tagDecl->namespaceID); assert(nsDecl != NULL); const xmlChar *prefix = (const xmlChar *)nsDecl->prefix; const xmlChar *localName = (const xmlChar *)tagDecl->localName; if (serialization->indent && (element->parent != element->doc->docNode)) xmlTextWriterWriteRawLen(serialization->writer,INDENT,1+depth); if (serialization->html || (tagDecl->namespaceID == serialization->defaultNS)) xmlTextWriterStartElement(serialization->writer,localName); else xmlTextWriterStartElementNS(serialization->writer,prefix,localName,NULL); if ((element->parent == serialization->doc->docNode) && !serialization->html) writeNamespaceDeclarations(serialization,element); writeAttributes(serialization,element); // Check if all children are text nodes. If this is true; we should treat them as if they are a single text // node, and not do any indentation. int allChildrenText = 1; for (DFNode *child = element->first; child != NULL; child = child->next) { if (child->tag != DOM_TEXT) allChildrenText = 0; } if (allChildrenText) { int oldIndent = serialization->indent; serialization->indent = 0; for (DFNode *child = element->first; child != NULL; child = child->next) writeNode(serialization,child,depth+2); serialization->indent = oldIndent; } else { for (DFNode *child = element->first; child != NULL; child = child->next) writeNode(serialization,child,depth+2); } if (serialization->indent && (element->first != NULL) && !allChildrenText) { if ((element->first != element->last) || (element->first->tag != DOM_TEXT)) xmlTextWriterWriteRawLen(serialization->writer,INDENT,1+depth); } if (serialization->html && (element->first == NULL) && HTML_requiresCloseTag(element->tag)) { xmlTextWriterWriteString(serialization->writer,(xmlChar *)""); } xmlTextWriterEndElement(serialization->writer); }
// FIXME: Not covered by tests void DFMarkupCompatibilityProcessAttr(DFMarkupCompatibility *mc, Tag attr, const char *value, DFNameMap *map) { const char **tokens = DFStringTokenize(value,isspace); for (int tokIndex = 0; tokens[tokIndex]; tokIndex++) { const char *component = tokens[tokIndex]; char *prefix = NULL; char *localName = NULL; const char *colon = strchr(component,':'); if (colon != NULL) { size_t colonPos = colon - component; prefix = DFSubstring(component,0,colonPos); localName = DFSubstring(component,colonPos+1,strlen(component)); } else { prefix = xstrdup(component); localName = NULL; } const char *nsIdStr = NULL; // Find namespace ID for prefix for (int recordIndex = mc->depth-1; recordIndex >= 0; recordIndex--) { MCRecord *record = &mc->records[recordIndex]; if (record->namespaces != NULL) nsIdStr = DFHashTableLookup(record->namespaces,prefix); } if (nsIdStr != NULL) { NamespaceID nsId = atoi(nsIdStr); Tag tag = 0; const NamespaceDecl *nsDecl = DFNameMapNamespaceForID(map,nsId); if (localName != NULL) tag = DFNameMapTagForName(map,nsDecl->namespaceURI,localName); switch (attr) { case MC_IGNORABLE: addDeclToRecord(&mc->records[mc->depth-1],nsId,tag,MCActionIgnore); break; case MC_PROCESSCONTENT: addDeclToRecord(&mc->records[mc->depth-1],nsId,tag,MCActionProcessContent); break; case MC_MUSTUNDERSTAND: addDeclToRecord(&mc->records[mc->depth-1],nsId,tag,MCActionMustUnderstand); break; } } free(prefix); free(localName); } free(tokens); }
DFNode *fromTidyNode(DFDocument *htmlDoc, TidyDoc tdoc, TidyNode tnode) { switch (tidyNodeGetType(tnode)) { case TidyNode_Text: { char *value = copyTidyNodeValue(tnode,tdoc); DFNode *result = DFCreateTextNode(htmlDoc,value); free(value); return result; } case TidyNode_CDATA: break; case TidyNode_Comment: break; case TidyNode_Root: printf("Have root\n"); break; default: { const char *name = tidyNodeGetName(tnode); if (name == NULL) { printf("NULL name for %p, type %d\n",tnode,tidyNodeGetType(tnode)); return NULL; } const NamespaceDecl *namespaceDecl = DFNameMapNamespaceForID(htmlDoc->map,NAMESPACE_HTML); Tag tag = DFNameMapTagForName(htmlDoc->map,namespaceDecl->namespaceURI,name); DFNode *element = DFCreateElement(htmlDoc,tag); for (TidyAttr tattr = tidyAttrFirst(tnode); tattr != NULL; tattr = tidyAttrNext(tattr)) { const char *name = tidyAttrName(tattr); const char *value = tidyAttrValue(tattr); if (value == NULL) // Can happen in case of the empty string value = "";; Tag attrTag = DFNameMapTagForName(htmlDoc->map,namespaceDecl->namespaceURI,name); DFSetAttribute(element,attrTag,value); } for (TidyNode tchild = tidyGetChild(tnode); tchild != NULL; tchild = tidyGetNext(tchild)) { DFNode *child = fromTidyNode(htmlDoc,tdoc,tchild); if (child != NULL) DFAppendChild(element,child); } return element; } } return NULL; }
static void writeNamespaceDeclarations(Serialization *serialization, DFNode *node) { NamespaceID count = DFNameMapNamespaceCount(serialization->doc->map); char *used = (char *)xcalloc(1,count); findUsedNamespaces(serialization->doc,node,used,count); for (NamespaceID nsId = 1; nsId < count; nsId++) { // don't write null namespace if (used[nsId]) { const NamespaceDecl *nsDecl = DFNameMapNamespaceForID(serialization->doc->map,nsId); const xmlChar *prefix = (const xmlChar *)nsDecl->prefix; const xmlChar *URI = (const xmlChar *)nsDecl->namespaceURI; if (nsId == serialization->defaultNS) xmlTextWriterWriteAttribute(serialization->writer,(const xmlChar *)"xmlns",URI); else xmlTextWriterWriteAttributeNS(serialization->writer,(const xmlChar *)"xmlns",prefix,NULL,URI); } } free(used); }
static void SAXStartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) { DFSAXParser *parser = (DFSAXParser *)ctx; const NamespaceDecl *namespaceDecl = DFNameMapNamespaceForID(parser->document->map,NAMESPACE_HTML); Tag tag = DFNameMapTagForName(parser->document->map,namespaceDecl->namespaceURI,(const char *)fullname); DFNode *element = DFCreateElement(parser->document,tag); if (atts != NULL) { for (int i = 0; atts[i] != NULL; i += 2) { const xmlChar *name = atts[i]; const xmlChar *value = atts[i+1]; Tag attrTag = DFNameMapTagForName(parser->document->map,namespaceDecl->namespaceURI,(const char *)name); DFSetAttribute(element,attrTag,(const char *)value); } } DFAppendChild(parser->parent,element); parser->parent = element; if (parser->document->root == NULL) parser->document->root = element; }
static void writeElement(Serialization *serialization, DFNode *element, int depth) { const TagDecl *tagDecl = DFNameMapNameForTag(serialization->doc->map,element->tag); assert(tagDecl != NULL); const NamespaceDecl *nsDecl = DFNameMapNamespaceForID(serialization->doc->map,tagDecl->namespaceID); assert(nsDecl != NULL); const xmlChar *prefix = (const xmlChar *)nsDecl->prefix; const xmlChar *localName = (const xmlChar *)tagDecl->localName; if (serialization->indent && (element->parent != element->doc->docNode)) xmlTextWriterWriteRawLen(serialization->writer,INDENT,1+depth); if (serialization->html || (tagDecl->namespaceID == serialization->defaultNS)) xmlTextWriterStartElement(serialization->writer,localName); else xmlTextWriterStartElementNS(serialization->writer,prefix,localName,NULL); if ((element->parent == serialization->doc->docNode) && !serialization->html) writeNamespaceDeclarations(serialization,element); writeAttributes(serialization,element); for (DFNode *child = element->first; child != NULL; child = child->next) writeNode(serialization,child,depth+2); if (serialization->indent && (element->first != NULL)) { if ((element->first != element->last) || (element->first->tag != DOM_TEXT)) xmlTextWriterWriteRawLen(serialization->writer,INDENT,1+depth); } if (serialization->html && (element->first == NULL) && HTML_requiresCloseTag(element->tag)) { xmlTextWriterWriteString(serialization->writer,(xmlChar *)""); } xmlTextWriterEndElement(serialization->writer); }
const char *DFTagURI(DFDocument *doc, Tag tag) { const TagDecl *tagDecl = DFNameMapNameForTag(doc->map,tag); const NamespaceDecl *nsDecl = (tagDecl == NULL) ? NULL : DFNameMapNamespaceForID(doc->map,tagDecl->namespaceID); return (nsDecl != NULL) ? nsDecl->namespaceURI : NULL; }