void MarkupAccumulator::serializeNodesWithNamespaces(Node& targetNode, EChildrenOnly childrenOnly, const Namespaces* namespaces, Vector<QualifiedName>* tagNamesToSkip) { if (tagNamesToSkip && is<Element>(targetNode)) { for (auto& name : *tagNamesToSkip) { if (downcast<Element>(targetNode).hasTagName(name)) return; } } Namespaces namespaceHash; if (namespaces) namespaceHash = *namespaces; else if (inXMLFragmentSerialization()) { // Make sure xml prefix and namespace are always known to uphold the constraints listed at http://www.w3.org/TR/xml-names11/#xmlReserved. namespaceHash.set(xmlAtom.impl(), XMLNames::xmlNamespaceURI.impl()); namespaceHash.set(XMLNames::xmlNamespaceURI.impl(), xmlAtom.impl()); } if (!childrenOnly) appendStartTag(targetNode, &namespaceHash); if (!(targetNode.document().isHTMLDocument() && elementCannotHaveEndTag(targetNode))) { #if ENABLE(TEMPLATE_ELEMENT) Node* current = targetNode.hasTagName(templateTag) ? downcast<HTMLTemplateElement>(targetNode).content()->firstChild() : targetNode.firstChild(); #else Node* current = targetNode.firstChild(); #endif for ( ; current; current = current->nextSibling()) serializeNodesWithNamespaces(*current, IncludeNode, &namespaceHash, tagNamesToSkip); } if (!childrenOnly) appendEndTag(targetNode); }
void MarkupAccumulator::appendNamespace(StringBuilder& result, const AtomicString& prefix, const AtomicString& namespaceURI, Namespaces& namespaces, bool allowEmptyDefaultNS) { namespaces.checkConsistency(); if (namespaceURI.isEmpty()) { // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-xhtml-syntax.html#xml-fragment-serialization-algorithm if (allowEmptyDefaultNS && namespaces.get(emptyAtom.impl())) { result.append(' '); result.append(xmlnsAtom.string()); result.appendLiteral("=\"\""); } return; } // Use emptyAtoms's impl() for both null and empty strings since the HashMap can't handle 0 as a key AtomicStringImpl* pre = prefix.isEmpty() ? emptyAtom.impl() : prefix.impl(); AtomicStringImpl* foundNS = namespaces.get(pre); if (foundNS != namespaceURI.impl() && !namespaces.get(namespaceURI.impl())) { namespaces.set(pre, namespaceURI.impl()); result.append(' '); result.append(xmlnsAtom.string()); if (!prefix.isEmpty()) { result.append(':'); result.append(prefix); } result.append('='); result.append('"'); appendAttributeValue(result, namespaceURI, false); result.append('"'); } }
String MarkupAccumulator::serializeNodes(Node& targetNode, EChildrenOnly childrenOnly, Vector<QualifiedName>* tagNamesToSkip) { Namespaces* namespaces = 0; Namespaces namespaceHash; if (!serializeAsHTMLDocument(targetNode)) { // Add pre-bound namespaces for XML fragments. namespaceHash.set(xmlAtom, XMLNames::xmlNamespaceURI); namespaces = &namespaceHash; } serializeNodesWithNamespaces(targetNode, childrenOnly, namespaces, tagNamesToSkip); return m_markup.toString(); }
String serializeNodes(MarkupAccumulator& accumulator, Node& targetNode, EChildrenOnly childrenOnly) { Namespaces* namespaces = nullptr; Namespaces namespaceHash; if (!accumulator.serializeAsHTMLDocument(targetNode)) { // Add pre-bound namespaces for XML fragments. namespaceHash.set(xmlAtom, XMLNames::xmlNamespaceURI); namespaces = &namespaceHash; } serializeNodesWithNamespaces<Strategy>(accumulator, targetNode, childrenOnly, namespaces); return accumulator.toString(); }
bool MarkupAccumulator::shouldAddNamespaceAttribute(const Attribute& attribute, Namespaces& namespaces) { // Don't add namespace attributes twice if (attribute.name() == XMLNSNames::xmlnsAttr) { namespaces.set(emptyAtom.impl(), attribute.value().impl()); return false; } QualifiedName xmlnsPrefixAttr(xmlnsAtom, attribute.localName(), XMLNSNames::xmlnsNamespaceURI); if (attribute.name() == xmlnsPrefixAttr) { namespaces.set(attribute.localName().impl(), attribute.value().impl()); return false; } return true; }
bool MarkupAccumulator::shouldAddNamespaceAttribute(const Attribute& attribute, Namespaces& namespaces) { namespaces.checkConsistency(); // Don't add namespace attributes twice // HTML Parser will create xmlns attributes without namespace for HTML elements, allow those as well. if (attribute.name().localName() == xmlnsAtom && (attribute.namespaceURI().isEmpty() || attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI)) { namespaces.set(emptyAtom.impl(), attribute.value().impl()); return false; } QualifiedName xmlnsPrefixAttr(xmlnsAtom, attribute.localName(), XMLNSNames::xmlnsNamespaceURI); if (attribute.name() == xmlnsPrefixAttr) { namespaces.set(attribute.localName().impl(), attribute.value().impl()); return false; } return true; }
void MarkupAccumulator::appendNamespace(StringBuilder& result, const AtomicString& prefix, const AtomicString& namespaceURI, Namespaces& namespaces) { if (namespaceURI.isEmpty()) return; const AtomicString& lookupKey = (!prefix) ? emptyAtom : prefix; AtomicString foundURI = namespaces.get(lookupKey); if (foundURI != namespaceURI) { namespaces.set(lookupKey, namespaceURI); result.append(' '); result.append(xmlnsAtom.string()); if (!prefix.isEmpty()) { result.append(':'); result.append(prefix); } result.appendLiteral("=\""); appendAttributeValue(result, namespaceURI, false); result.append('"'); } }
void MarkupAccumulator::appendNamespace(StringBuilder& result, const AtomicString& prefix, const AtomicString& namespaceURI, Namespaces& namespaces) { if (namespaceURI.isEmpty()) return; // Use emptyAtoms's impl() for both null and empty strings since the HashMap can't handle 0 as a key StringImpl* pre = prefix.isEmpty() ? emptyAtom.impl() : prefix.impl(); StringImpl* foundNS = namespaces.get(pre); if (foundNS != namespaceURI.impl()) { namespaces.set(pre, namespaceURI.impl()); result.append(' '); result.append(xmlnsAtom.string()); if (!prefix.isEmpty()) { result.append(':'); result.append(prefix); } result.appendLiteral("=\""); appendAttributeValue(result, namespaceURI, false); result.append('"'); } }
bool MarkupAccumulator::shouldAddNamespaceElement(const Element& element, Namespaces& namespaces) { // Don't add namespace attribute if it is already defined for this elem. const AtomicString& prefix = element.prefix(); if (prefix.isEmpty()) { if (element.hasAttribute(xmlnsAtom)) { namespaces.set(emptyAtom, element.namespaceURI()); return false; } return true; } return !element.hasAttribute(WTF::xmlnsWithColon + prefix); }
void MarkupAccumulator::appendNamespace(StringBuilder& result, const AtomicString& prefix, const AtomicString& namespaceURI, Namespaces& namespaces, bool allowEmptyDefaultNS) { namespaces.checkConsistency(); if (namespaceURI.isEmpty()) { // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-xhtml-syntax.html#xml-fragment-serialization-algorithm if (allowEmptyDefaultNS && namespaces.get(emptyAtom.impl())) { result.append(' '); result.append(xmlnsAtom.string()); result.appendLiteral("=\"\""); } return; } // Use emptyAtoms's impl() for both null and empty strings since the HashMap can't handle 0 as a key AtomicStringImpl* pre = prefix.isEmpty() ? emptyAtom.impl() : prefix.impl(); AtomicStringImpl* foundNS = namespaces.get(pre); if (foundNS != namespaceURI.impl()) { namespaces.set(pre, namespaceURI.impl()); // Add namespace to prefix pair so we can do constraint checking later. if (inXMLFragmentSerialization() && !prefix.isEmpty()) namespaces.set(namespaceURI.impl(), pre); // Make sure xml prefix and namespace are always known to uphold the constraints listed at http://www.w3.org/TR/xml-names11/#xmlReserved. if (namespaceURI.impl() == XMLNames::xmlNamespaceURI.impl()) return; result.append(' '); result.append(xmlnsAtom.string()); if (!prefix.isEmpty()) { result.append(':'); result.append(prefix); } result.append('='); result.append('"'); appendAttributeValue(result, namespaceURI, false); result.append('"'); } }
void MarkupAccumulator::generateUniquePrefix(QualifiedName& prefixedName, const Namespaces& namespaces) { // http://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#normalizeDocumentAlgo // Find a prefix following the pattern "NS" + index (starting at 1) and make sure this // prefix is not declared in the current scope. StringBuilder builder; do { builder.clear(); builder.append("NS"); builder.appendNumber(++m_prefixLevel); const AtomicString& name = builder.toAtomicString(); if (!namespaces.get(name.impl())) { prefixedName.setPrefix(name); return; } } while (true); }