diff --git a/CHANGELOG.md b/CHANGELOG.md index db1d50c3bb..005894cd31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,20 +6,36 @@ Nokogiri follows [Semantic Versioning](https://semver.org/), please see the [REA ## next / unreleased -### Dependencies +### Added + +__HTML5 support__ has been added (to CRuby only) by merging [Nokogumbo](https://github.com/rubys/nokogumbo) into Nokogiri. The Nokogumbo public API has been preserved, so this functionality is available under the `Nokogiri::HTML5` namespace. [[#2204](https://github.com/sparklemotion/nokogiri/issues/2204)] + +Please note that HTML5 support is not available for JRuby in this version. However, we feel it is important to think about JRuby and we hope to work on this in the future. If you're interested in helping with HTML5 support on JRuby, please reach out to the maintainers by commenting on issue [#2227](https://github.com/sparklemotion/nokogiri/issues/2227). -* [MRI] Upgrade mini_portile2 dependency from `~> 2.5.0` to `~> 2.5.1`. +Please also note that the `Nokogiri::HTML` parse methods still use libxml2's HTML4 parser in the v1.12 release series. Future releases of Nokogiri may change this behavior, but we'll proceed cautiously to avoid breaking existing applications. + +Many thanks to Sam Ruby, Steve Checkoway, and Craig Barnes for creating and maintaining Nokogumbo and supporting the Gumbo HTML5 parser. They're now Nokogiri core contributors with all the powers and privileges pertaining thereto. 🙌 ### Changed -* Introduce `Nokogiri::XML::ParseOptions::DEFAULT_XSLT` which adds the libxslt-preferred options of `NOENT | DTDLOAD | DTDATTR | NOCDATA` to `ParseOptions::DEFAULT_XML`. -* `Nokogiri.XSLT` parses the stylesheet using `ParseOptions::DEFAULT_XSLT`, which should make some edge-case XSL transformations match libxslt's default behavior. [[#1940](https://github.com/sparklemotion/nokogiri/issues/1940)] +* Introduce a new constant, `Nokogiri::XML::ParseOptions::DEFAULT_XSLT`, which adds the libxslt-preferred options of `NOENT | DTDLOAD | DTDATTR | NOCDATA` to `ParseOptions::DEFAULT_XML`. +* `Nokogiri.XSLT` parses stylesheets using `ParseOptions::DEFAULT_XSLT`, which should make some edge-case XSL transformations match libxslt's default behavior. [[#1940](https://github.com/sparklemotion/nokogiri/issues/1940)] + + +### Fixed + +* [CRuby] Namespaced attributes are handled properly when their parent node is reparented into another document. Previously, the namespace may have gotten dropped. [[#2228](https://github.com/sparklemotion/nokogiri/issues/2228)] ### Improved -* [MRI] Speed up (slightly) the compile time of packaged libraries `libiconv`, `libxml2`, and `libxslt` by using autoconf's `--disable-dependency-tracking` option. +* [CRuby] Speed up (slightly) the compile time of packaged libraries `libiconv`, `libxml2`, and `libxslt` by using autoconf's `--disable-dependency-tracking` option. ("ruby" platform gem only.) + + +### Dependencies + +* [CRuby] Upgrade mini_portile2 dependency from `~> 2.5.0` to `~> 2.5.1`. ("ruby" platform gem only.) ## 1.11.3 / 2021-04-07 diff --git a/ext/java/nokogiri/XmlDocument.java b/ext/java/nokogiri/XmlDocument.java index 1942cb4891..0d859e730f 100644 --- a/ext/java/nokogiri/XmlDocument.java +++ b/ext/java/nokogiri/XmlDocument.java @@ -657,17 +657,17 @@ private static class DocumentBuilderFactoryHolder } String algorithmURI = null; switch (mode) { - case 0: // XML_C14N_1_0 - if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS; } - else { algorithmURI = Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS; } - break; - case 1: // XML_C14N_EXCLUSIVE_1_0 - if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS; } - else { algorithmURI = Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS; } - break; - case 2: // XML_C14N_1_1 = 2 - if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS; } - else { algorithmURI = Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS; } + case 0: // XML_C14N_1_0 + if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS; } + else { algorithmURI = Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS; } + break; + case 1: // XML_C14N_EXCLUSIVE_1_0 + if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS; } + else { algorithmURI = Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS; } + break; + case 2: // XML_C14N_1_1 = 2 + if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS; } + else { algorithmURI = Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS; } } try { Canonicalizer canonicalizer = Canonicalizer.getInstance(algorithmURI); diff --git a/ext/java/nokogiri/XmlElementContent.java b/ext/java/nokogiri/XmlElementContent.java index 10b35c3e9d..0ff13e2da1 100644 --- a/ext/java/nokogiri/XmlElementContent.java +++ b/ext/java/nokogiri/XmlElementContent.java @@ -142,11 +142,11 @@ public IRubyObject value(Ruby runtime) right = runtime.getNil(); switch (type) { - case SEQ: - case OR: - applyGroup(runtime, klass, doc, iter); - default: - // noop + case SEQ: + case OR: + applyGroup(runtime, klass, doc, iter); + default: + // noop } } diff --git a/ext/java/nokogiri/XmlNode.java b/ext/java/nokogiri/XmlNode.java index 25f072c9f7..9cab7c0823 100644 --- a/ext/java/nokogiri/XmlNode.java +++ b/ext/java/nokogiri/XmlNode.java @@ -1516,56 +1516,56 @@ public class XmlNode extends RubyObject { String type; switch (node.getNodeType()) { - case Node.ELEMENT_NODE: - if (this instanceof XmlElementDecl) { - type = "ELEMENT_DECL"; - } else if (this instanceof XmlAttributeDecl) { - type = "ATTRIBUTE_DECL"; - } else if (this instanceof XmlEntityDecl) { - type = "ENTITY_DECL"; - } else { - type = "ELEMENT_NODE"; - } - break; - case Node.ATTRIBUTE_NODE: - type = "ATTRIBUTE_NODE"; - break; - case Node.TEXT_NODE: - type = "TEXT_NODE"; - break; - case Node.CDATA_SECTION_NODE: - type = "CDATA_SECTION_NODE"; - break; - case Node.ENTITY_REFERENCE_NODE: - type = "ENTITY_REF_NODE"; - break; - case Node.ENTITY_NODE: - type = "ENTITY_NODE"; - break; - case Node.PROCESSING_INSTRUCTION_NODE: - type = "PI_NODE"; - break; - case Node.COMMENT_NODE: - type = "COMMENT_NODE"; - break; - case Node.DOCUMENT_NODE: - if (this instanceof HtmlDocument) { - type = "HTML_DOCUMENT_NODE"; - } else { - type = "DOCUMENT_NODE"; - } - break; - case Node.DOCUMENT_TYPE_NODE: - type = "DOCUMENT_TYPE_NODE"; - break; - case Node.DOCUMENT_FRAGMENT_NODE: - type = "DOCUMENT_FRAG_NODE"; - break; - case Node.NOTATION_NODE: - type = "NOTATION_NODE"; - break; - default: - return context.runtime.newFixnum(0); + case Node.ELEMENT_NODE: + if (this instanceof XmlElementDecl) { + type = "ELEMENT_DECL"; + } else if (this instanceof XmlAttributeDecl) { + type = "ATTRIBUTE_DECL"; + } else if (this instanceof XmlEntityDecl) { + type = "ENTITY_DECL"; + } else { + type = "ELEMENT_NODE"; + } + break; + case Node.ATTRIBUTE_NODE: + type = "ATTRIBUTE_NODE"; + break; + case Node.TEXT_NODE: + type = "TEXT_NODE"; + break; + case Node.CDATA_SECTION_NODE: + type = "CDATA_SECTION_NODE"; + break; + case Node.ENTITY_REFERENCE_NODE: + type = "ENTITY_REF_NODE"; + break; + case Node.ENTITY_NODE: + type = "ENTITY_NODE"; + break; + case Node.PROCESSING_INSTRUCTION_NODE: + type = "PI_NODE"; + break; + case Node.COMMENT_NODE: + type = "COMMENT_NODE"; + break; + case Node.DOCUMENT_NODE: + if (this instanceof HtmlDocument) { + type = "HTML_DOCUMENT_NODE"; + } else { + type = "DOCUMENT_NODE"; + } + break; + case Node.DOCUMENT_TYPE_NODE: + type = "DOCUMENT_TYPE_NODE"; + break; + case Node.DOCUMENT_FRAGMENT_NODE: + type = "DOCUMENT_FRAG_NODE"; + break; + case Node.NOTATION_NODE: + type = "NOTATION_NODE"; + break; + default: + return context.runtime.newFixnum(0); } return getNokogiriClass(context.runtime, "Nokogiri::XML::Node").getConstant(type); @@ -1676,23 +1676,23 @@ protected enum AdoptScheme { Node parent = thisNode.getParentNode(); switch (scheme) { - case CHILD: - Node[] children = adoptAsChild(thisNode, otherNode); - if (children.length == 1 && otherNode == children[0]) { + case CHILD: + Node[] children = adoptAsChild(thisNode, otherNode); + if (children.length == 1 && otherNode == children[0]) { + break; + } else { + nodeOrTags = nodeArrayToRubyArray(context.runtime, children); + } + break; + case PREV_SIBLING: + adoptAsPrevSibling(context, parent, thisNode, otherNode); + break; + case NEXT_SIBLING: + adoptAsNextSibling(context, parent, thisNode, otherNode); + break; + case REPLACEMENT: + adoptAsReplacement(context, parent, thisNode, otherNode); break; - } else { - nodeOrTags = nodeArrayToRubyArray(context.runtime, children); - } - break; - case PREV_SIBLING: - adoptAsPrevSibling(context, parent, thisNode, otherNode); - break; - case NEXT_SIBLING: - adoptAsNextSibling(context, parent, thisNode, otherNode); - break; - case REPLACEMENT: - adoptAsReplacement(context, parent, thisNode, otherNode); - break; } } catch (Exception e) { throw context.runtime.newRuntimeError(e.toString()); diff --git a/ext/java/nokogiri/XmlXpathContext.java b/ext/java/nokogiri/XmlXpathContext.java index b65e1d9361..1f720c0806 100644 --- a/ext/java/nokogiri/XmlXpathContext.java +++ b/ext/java/nokogiri/XmlXpathContext.java @@ -203,15 +203,15 @@ public class XmlXpathContext extends RubyObject } switch (xobj.getType()) { - case XObject.CLASS_BOOLEAN : - return context.runtime.newBoolean(xobj.bool()); - case XObject.CLASS_NUMBER : - return context.runtime.newFloat(xobj.num()); - case XObject.CLASS_NODESET : - IRubyObject[] nodes = nodeListToRubyArray(context.runtime, xobj.nodelist()); - return XmlNodeSet.newNodeSet(context.runtime, nodes, this.context); - default : - return context.runtime.newString(xobj.str()); + case XObject.CLASS_BOOLEAN : + return context.runtime.newBoolean(xobj.bool()); + case XObject.CLASS_NUMBER : + return context.runtime.newFloat(xobj.num()); + case XObject.CLASS_NODESET : + IRubyObject[] nodes = nodeListToRubyArray(context.runtime, xobj.nodelist()); + return XmlNodeSet.newNodeSet(context.runtime, nodes, this.context); + default : + return context.runtime.newString(xobj.str()); } } diff --git a/ext/java/nokogiri/XsltStylesheet.java b/ext/java/nokogiri/XsltStylesheet.java index e56cdc1851..9bb322c46c 100644 --- a/ext/java/nokogiri/XsltStylesheet.java +++ b/ext/java/nokogiri/XsltStylesheet.java @@ -213,12 +213,12 @@ public class XsltStylesheet extends RubyObject } switch (elistener.getErrorType()) { - case ERROR: - case FATAL: - throw runtime.newRuntimeError(elistener.getErrorMessage()); - case WARNING: - default: - // no-op + case ERROR: + case FATAL: + throw runtime.newRuntimeError(elistener.getErrorMessage()); + case WARNING: + default: + // no-op } if (stringResult == null) { diff --git a/ext/java/nokogiri/internals/NokogiriHelpers.java b/ext/java/nokogiri/internals/NokogiriHelpers.java index a211ffbff1..1625c9f8b3 100644 --- a/ext/java/nokogiri/internals/NokogiriHelpers.java +++ b/ext/java/nokogiri/internals/NokogiriHelpers.java @@ -116,59 +116,59 @@ public class NokogiriHelpers if (node == null) { return runtime.getNil(); } // this is slow; need a way to cache nokogiri classes/modules somewhere switch (node.getNodeType()) { - case Node.ELEMENT_NODE: - XmlElement xmlElement = (XmlElement) NokogiriService.XML_ELEMENT_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, - "Nokogiri::XML::Element")); - xmlElement.setNode(runtime, node); - return xmlElement; - case Node.ATTRIBUTE_NODE: - XmlAttr xmlAttr = (XmlAttr) NokogiriService.XML_ATTR_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, - "Nokogiri::XML::Attr")); - xmlAttr.setNode(runtime, node); - return xmlAttr; - case Node.TEXT_NODE: - XmlText xmlText = (XmlText) NokogiriService.XML_TEXT_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, - "Nokogiri::XML::Text")); - xmlText.setNode(runtime, node); - return xmlText; - case Node.COMMENT_NODE: - XmlComment xmlComment = (XmlComment) NokogiriService.XML_COMMENT_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, - "Nokogiri::XML::Comment")); - xmlComment.setNode(runtime, node); - return xmlComment; - case Node.ENTITY_NODE: - return new XmlNode(runtime, getNokogiriClass(runtime, "Nokogiri::XML::EntityDecl"), node); - case Node.ENTITY_REFERENCE_NODE: - XmlEntityReference xmlEntityRef = (XmlEntityReference) NokogiriService.XML_ENTITY_REFERENCE_ALLOCATOR.allocate(runtime, - getNokogiriClass(runtime, "Nokogiri::XML::EntityReference")); - xmlEntityRef.setNode(runtime, node); - return xmlEntityRef; - case Node.PROCESSING_INSTRUCTION_NODE: - XmlProcessingInstruction xmlProcessingInstruction = (XmlProcessingInstruction) - NokogiriService.XML_PROCESSING_INSTRUCTION_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, - "Nokogiri::XML::ProcessingInstruction")); - xmlProcessingInstruction.setNode(runtime, node); - return xmlProcessingInstruction; - case Node.CDATA_SECTION_NODE: - XmlCdata xmlCdata = (XmlCdata) NokogiriService.XML_CDATA_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, - "Nokogiri::XML::CDATA")); - xmlCdata.setNode(runtime, node); - return xmlCdata; - case Node.DOCUMENT_NODE: - XmlDocument xmlDocument = (XmlDocument) NokogiriService.XML_DOCUMENT_ALLOCATOR.allocate(runtime, - getNokogiriClass(runtime, "Nokogiri::XML::Document")); - xmlDocument.setDocumentNode(runtime, (Document) node); - return xmlDocument; - case Node.DOCUMENT_TYPE_NODE: - XmlDtd xmlDtd = (XmlDtd) NokogiriService.XML_DTD_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, - "Nokogiri::XML::DTD")); - xmlDtd.setNode(runtime, node); - return xmlDtd; - default: - XmlNode xmlNode = (XmlNode) NokogiriService.XML_NODE_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, - "Nokogiri::XML::Node")); - xmlNode.setNode(runtime, node); - return xmlNode; + case Node.ELEMENT_NODE: + XmlElement xmlElement = (XmlElement) NokogiriService.XML_ELEMENT_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, + "Nokogiri::XML::Element")); + xmlElement.setNode(runtime, node); + return xmlElement; + case Node.ATTRIBUTE_NODE: + XmlAttr xmlAttr = (XmlAttr) NokogiriService.XML_ATTR_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, + "Nokogiri::XML::Attr")); + xmlAttr.setNode(runtime, node); + return xmlAttr; + case Node.TEXT_NODE: + XmlText xmlText = (XmlText) NokogiriService.XML_TEXT_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, + "Nokogiri::XML::Text")); + xmlText.setNode(runtime, node); + return xmlText; + case Node.COMMENT_NODE: + XmlComment xmlComment = (XmlComment) NokogiriService.XML_COMMENT_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, + "Nokogiri::XML::Comment")); + xmlComment.setNode(runtime, node); + return xmlComment; + case Node.ENTITY_NODE: + return new XmlNode(runtime, getNokogiriClass(runtime, "Nokogiri::XML::EntityDecl"), node); + case Node.ENTITY_REFERENCE_NODE: + XmlEntityReference xmlEntityRef = (XmlEntityReference) NokogiriService.XML_ENTITY_REFERENCE_ALLOCATOR.allocate(runtime, + getNokogiriClass(runtime, "Nokogiri::XML::EntityReference")); + xmlEntityRef.setNode(runtime, node); + return xmlEntityRef; + case Node.PROCESSING_INSTRUCTION_NODE: + XmlProcessingInstruction xmlProcessingInstruction = (XmlProcessingInstruction) + NokogiriService.XML_PROCESSING_INSTRUCTION_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, + "Nokogiri::XML::ProcessingInstruction")); + xmlProcessingInstruction.setNode(runtime, node); + return xmlProcessingInstruction; + case Node.CDATA_SECTION_NODE: + XmlCdata xmlCdata = (XmlCdata) NokogiriService.XML_CDATA_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, + "Nokogiri::XML::CDATA")); + xmlCdata.setNode(runtime, node); + return xmlCdata; + case Node.DOCUMENT_NODE: + XmlDocument xmlDocument = (XmlDocument) NokogiriService.XML_DOCUMENT_ALLOCATOR.allocate(runtime, + getNokogiriClass(runtime, "Nokogiri::XML::Document")); + xmlDocument.setDocumentNode(runtime, (Document) node); + return xmlDocument; + case Node.DOCUMENT_TYPE_NODE: + XmlDtd xmlDtd = (XmlDtd) NokogiriService.XML_DTD_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, + "Nokogiri::XML::DTD")); + xmlDtd.setNode(runtime, node); + return xmlDtd; + default: + XmlNode xmlNode = (XmlNode) NokogiriService.XML_NODE_ALLOCATOR.allocate(runtime, getNokogiriClass(runtime, + "Nokogiri::XML::Node")); + xmlNode.setNode(runtime, node); + return xmlNode; } } diff --git a/ext/java/nokogiri/internals/SaveContextVisitor.java b/ext/java/nokogiri/internals/SaveContextVisitor.java index ced4630811..e5f0e3d0ac 100644 --- a/ext/java/nokogiri/internals/SaveContextVisitor.java +++ b/ext/java/nokogiri/internals/SaveContextVisitor.java @@ -296,30 +296,30 @@ public class SaveContextVisitor for (int i = 0; i < str.length(); i++) { char c; switch (c = str.charAt(i)) { - case '\n': - buffer.append(" "); - break; - case '\r': - buffer.append(" "); - break; - case '\t': - buffer.append(" "); - break; - case '"': - if (htmlDoc) { buffer.append("%22"); } - else { buffer.append("""); } - break; - case '<': - buffer.append("<"); - break; - case '>': - buffer.append(">"); - break; - case '&': - buffer.append("&"); - break; - default: - buffer.append(c); + case '\n': + buffer.append(" "); + break; + case '\r': + buffer.append(" "); + break; + case '\t': + buffer.append(" "); + break; + case '"': + if (htmlDoc) { buffer.append("%22"); } + else { buffer.append("""); } + break; + case '<': + buffer.append("<"); + break; + case '>': + buffer.append(">"); + break; + case '&': + buffer.append("&"); + break; + default: + buffer.append(c); } } diff --git a/ext/java/nokogiri/internals/c14n/CanonicalizerBase.java b/ext/java/nokogiri/internals/c14n/CanonicalizerBase.java index 214c46a286..7a81f428f5 100644 --- a/ext/java/nokogiri/internals/c14n/CanonicalizerBase.java +++ b/ext/java/nokogiri/internals/c14n/CanonicalizerBase.java @@ -202,75 +202,75 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi do { switch (currentNode.getNodeType()) { - case Node.ENTITY_NODE : - case Node.NOTATION_NODE : - case Node.ATTRIBUTE_NODE : - // illegal node type during traversal - throw new CanonicalizationException("empty"); - - case Node.DOCUMENT_FRAGMENT_NODE : - case Node.DOCUMENT_NODE : - ns.outputNodePush(); - sibling = currentNode.getFirstChild(); - break; - - case Node.COMMENT_NODE : - if (includeComments) { - outputCommentToWriter((Comment) currentNode, writer, documentLevel); - } - break; - - case Node.PROCESSING_INSTRUCTION_NODE : - outputPItoWriter((ProcessingInstruction) currentNode, writer, documentLevel); - break; + case Node.ENTITY_NODE : + case Node.NOTATION_NODE : + case Node.ATTRIBUTE_NODE : + // illegal node type during traversal + throw new CanonicalizationException("empty"); + + case Node.DOCUMENT_FRAGMENT_NODE : + case Node.DOCUMENT_NODE : + ns.outputNodePush(); + sibling = currentNode.getFirstChild(); + break; - case Node.TEXT_NODE : - case Node.CDATA_SECTION_NODE : - outputTextToWriter(currentNode.getNodeValue(), writer); - break; + case Node.COMMENT_NODE : + if (includeComments) { + outputCommentToWriter((Comment) currentNode, writer, documentLevel); + } + break; - case Node.ELEMENT_NODE : - documentLevel = NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; - if (currentNode == excludeNode) { + case Node.PROCESSING_INSTRUCTION_NODE : + outputPItoWriter((ProcessingInstruction) currentNode, writer, documentLevel); break; - } - if (filter != null && !filter.includeNodes(currentNode, parentNode)) { + + case Node.TEXT_NODE : + case Node.CDATA_SECTION_NODE : + outputTextToWriter(currentNode.getNodeValue(), writer); break; - } - Element currentElement = (Element)currentNode; - //Add a level to the nssymbtable. So latter can be pop-back. - ns.outputNodePush(); - writer.write('<'); - String name = currentElement.getTagName(); - UtfHelpper.writeByte(name, writer, cache); - - Iterator attrs = this.handleAttributesSubtree(currentElement, ns); - if (attrs != null) { - //we output all Attrs which are available - while (attrs.hasNext()) { - Attr attr = attrs.next(); - outputAttrToWriter(attr.getNodeName(), attr.getNodeValue(), writer, cache); + case Node.ELEMENT_NODE : + documentLevel = NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; + if (currentNode == excludeNode) { + break; + } + if (filter != null && !filter.includeNodes(currentNode, parentNode)) { + break; + } + + Element currentElement = (Element)currentNode; + //Add a level to the nssymbtable. So latter can be pop-back. + ns.outputNodePush(); + writer.write('<'); + String name = currentElement.getTagName(); + UtfHelpper.writeByte(name, writer, cache); + + Iterator attrs = this.handleAttributesSubtree(currentElement, ns); + if (attrs != null) { + //we output all Attrs which are available + while (attrs.hasNext()) { + Attr attr = attrs.next(); + outputAttrToWriter(attr.getNodeName(), attr.getNodeValue(), writer, cache); + } } - } - writer.write('>'); - sibling = currentNode.getFirstChild(); - if (sibling == null) { - writer.write(END_TAG); - UtfHelpper.writeStringToUtf8(name, writer); writer.write('>'); - //We finished with this level, pop to the previous definitions. - ns.outputNodePop(); - if (parentNode != null) { - sibling = currentNode.getNextSibling(); + sibling = currentNode.getFirstChild(); + if (sibling == null) { + writer.write(END_TAG); + UtfHelpper.writeStringToUtf8(name, writer); + writer.write('>'); + //We finished with this level, pop to the previous definitions. + ns.outputNodePop(); + if (parentNode != null) { + sibling = currentNode.getNextSibling(); + } + } else { + parentNode = currentElement; } - } else { - parentNode = currentElement; - } - break; - case Node.DOCUMENT_TYPE_NODE : - default : - break; + break; + case Node.DOCUMENT_TYPE_NODE : + default : + break; } while (sibling == null && parentNode != null) { writer.write(END_TAG); @@ -477,37 +477,37 @@ abstract Iterator handleAttributesSubtree(Element element, NameSpaceSymbTa switch (c) { - case '&' : - toWrite = AMP; - break; + case '&' : + toWrite = AMP; + break; - case '<' : - toWrite = LT; - break; + case '<' : + toWrite = LT; + break; - case '"' : - toWrite = QUOT; - break; + case '"' : + toWrite = QUOT; + break; - case 0x09 : // '\t' - toWrite = X9; - break; + case 0x09 : // '\t' + toWrite = X9; + break; - case 0x0A : // '\n' - toWrite = XA; - break; + case 0x0A : // '\n' + toWrite = XA; + break; - case 0x0D : // '\r' - toWrite = XD; - break; + case 0x0D : // '\r' + toWrite = XD; + break; - default : - if (c < 0x80) { - writer.write(c); - } else { - UtfHelpper.writeCharToUtf8(c, writer); - } - continue; + default : + if (c < 0x80) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c, writer); + } + continue; } writer.write(toWrite); } @@ -629,29 +629,29 @@ abstract Iterator handleAttributesSubtree(Element element, NameSpaceSymbTa switch (c) { - case '&' : - toWrite = AMP; - break; + case '&' : + toWrite = AMP; + break; - case '<' : - toWrite = LT; - break; + case '<' : + toWrite = LT; + break; - case '>' : - toWrite = GT; - break; + case '>' : + toWrite = GT; + break; - case 0xD : - toWrite = XD; - break; + case 0xD : + toWrite = XD; + break; - default : - if (c < 0x80) { - writer.write(c); - } else { - UtfHelpper.writeCharToUtf8(c, writer); - } - continue; + default : + if (c < 0x80) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c, writer); + } + continue; } writer.write(toWrite); } diff --git a/ext/java/nokogiri/internals/c14n/XMLUtils.java b/ext/java/nokogiri/internals/c14n/XMLUtils.java index 2a9190f8c2..c29de56601 100644 --- a/ext/java/nokogiri/internals/c14n/XMLUtils.java +++ b/ext/java/nokogiri/internals/c14n/XMLUtils.java @@ -195,43 +195,43 @@ public class XMLUtils final String namespaceNs = Constants.NamespaceSpecNS; do { switch (node.getNodeType()) { - case Node.ELEMENT_NODE : - Element element = (Element) node; - if (!element.hasChildNodes()) { - break; - } - if (element.hasAttributes()) { - NamedNodeMap attributes = element.getAttributes(); - int attributesLength = attributes.getLength(); - - for (Node child = element.getFirstChild(); child != null; - child = child.getNextSibling()) { + case Node.ELEMENT_NODE : + Element element = (Element) node; + if (!element.hasChildNodes()) { + break; + } + if (element.hasAttributes()) { + NamedNodeMap attributes = element.getAttributes(); + int attributesLength = attributes.getLength(); - if (child.getNodeType() != Node.ELEMENT_NODE) { - continue; - } - Element childElement = (Element) child; + for (Node child = element.getFirstChild(); child != null; + child = child.getNextSibling()) { - for (int i = 0; i < attributesLength; i++) { - Attr currentAttr = (Attr) attributes.item(i); - if (!namespaceNs.equals(currentAttr.getNamespaceURI())) { + if (child.getNodeType() != Node.ELEMENT_NODE) { continue; } - if (childElement.hasAttributeNS(namespaceNs, - currentAttr.getLocalName())) { - continue; + Element childElement = (Element) child; + + for (int i = 0; i < attributesLength; i++) { + Attr currentAttr = (Attr) attributes.item(i); + if (!namespaceNs.equals(currentAttr.getNamespaceURI())) { + continue; + } + if (childElement.hasAttributeNS(namespaceNs, + currentAttr.getLocalName())) { + continue; + } + childElement.setAttributeNS(namespaceNs, + currentAttr.getName(), + currentAttr.getNodeValue()); } - childElement.setAttributeNS(namespaceNs, - currentAttr.getName(), - currentAttr.getNodeValue()); } } - } - case Node.ENTITY_REFERENCE_NODE : - case Node.DOCUMENT_NODE : - parent = node; - sibling = node.getFirstChild(); - break; + case Node.ENTITY_REFERENCE_NODE : + case Node.DOCUMENT_NODE : + parent = node; + sibling = node.getFirstChild(); + break; } while ((sibling == null) && (parent != null)) { sibling = parent.getNextSibling(); diff --git a/ext/java/nokogiri/internals/dom2dtm/DOM2DTM.java b/ext/java/nokogiri/internals/dom2dtm/DOM2DTM.java index 36b17023dc..652caaab5d 100644 --- a/ext/java/nokogiri/internals/dom2dtm/DOM2DTM.java +++ b/ext/java/nokogiri/internals/dom2dtm/DOM2DTM.java @@ -885,26 +885,26 @@ else if (PROCESSING_INSTRUCTION_NODE == nexttype) { { switch (node.getNodeType()) { - case Node.DOCUMENT_FRAGMENT_NODE : - case Node.DOCUMENT_NODE : - case Node.ELEMENT_NODE : { - for (Node child = node.getFirstChild(); null != child; - child = child.getNextSibling()) { - getNodeData(child, buf); + case Node.DOCUMENT_FRAGMENT_NODE : + case Node.DOCUMENT_NODE : + case Node.ELEMENT_NODE : { + for (Node child = node.getFirstChild(); null != child; + child = child.getNextSibling()) { + getNodeData(child, buf); + } } - } - break; - case Node.TEXT_NODE : - case Node.CDATA_SECTION_NODE : - case Node.ATTRIBUTE_NODE : // Never a child but might be our starting node - buf.append(node.getNodeValue()); - break; - case Node.PROCESSING_INSTRUCTION_NODE : - // warning(XPATHErrorResources.WG_PARSING_AND_PREPARING); - break; - default : - // ignore break; + case Node.TEXT_NODE : + case Node.CDATA_SECTION_NODE : + case Node.ATTRIBUTE_NODE : // Never a child but might be our starting node + buf.append(node.getNodeValue()); + break; + case Node.PROCESSING_INSTRUCTION_NODE : + // warning(XPATHErrorResources.WG_PARSING_AND_PREPARING); + break; + default : + // ignore + break; } } @@ -943,30 +943,30 @@ else if (PROCESSING_INSTRUCTION_NODE == nexttype) { short type = getNodeType(nodeHandle); switch (type) { - case DTM.NAMESPACE_NODE : { - Node node = getNode(nodeHandle); - - // assume not null. - name = node.getNodeName(); - if (name.startsWith("xmlns:")) { - name = QName.getLocalPart(name); - } else if (name.equals("xmlns")) { - name = ""; + case DTM.NAMESPACE_NODE : { + Node node = getNode(nodeHandle); + + // assume not null. + name = node.getNodeName(); + if (name.startsWith("xmlns:")) { + name = QName.getLocalPart(name); + } else if (name.equals("xmlns")) { + name = ""; + } } - } - break; - case DTM.ATTRIBUTE_NODE : - case DTM.ELEMENT_NODE : - case DTM.ENTITY_REFERENCE_NODE : - case DTM.PROCESSING_INSTRUCTION_NODE : { - Node node = getNode(nodeHandle); - - // assume not null. - name = node.getNodeName(); - } - break; - default : - name = ""; + break; + case DTM.ATTRIBUTE_NODE : + case DTM.ELEMENT_NODE : + case DTM.ENTITY_REFERENCE_NODE : + case DTM.PROCESSING_INSTRUCTION_NODE : { + Node node = getNode(nodeHandle); + + // assume not null. + name = node.getNodeName(); + } + break; + default : + name = ""; } return name; @@ -1056,29 +1056,29 @@ else if (PROCESSING_INSTRUCTION_NODE == nexttype) { short type = getNodeType(nodeHandle); switch (type) { - case DTM.NAMESPACE_NODE : { - Node node = getNode(nodeHandle); + case DTM.NAMESPACE_NODE : { + Node node = getNode(nodeHandle); - // assume not null. - String qname = node.getNodeName(); - int index = qname.indexOf(':'); + // assume not null. + String qname = node.getNodeName(); + int index = qname.indexOf(':'); - prefix = (index < 0) ? "" : qname.substring(index + 1); - } - break; - case DTM.ATTRIBUTE_NODE : - case DTM.ELEMENT_NODE : { - Node node = getNode(nodeHandle); + prefix = (index < 0) ? "" : qname.substring(index + 1); + } + break; + case DTM.ATTRIBUTE_NODE : + case DTM.ELEMENT_NODE : { + Node node = getNode(nodeHandle); - // assume not null. - String qname = node.getNodeName(); - int index = qname.indexOf(':'); + // assume not null. + String qname = node.getNodeName(); + int index = qname.indexOf(':'); - prefix = (index < 0) ? "" : qname.substring(0, index); - } - break; - default : - prefix = ""; + prefix = (index < 0) ? "" : qname.substring(0, index); + } + break; + default : + prefix = ""; } return prefix; @@ -1616,38 +1616,38 @@ else if (PROCESSING_INSTRUCTION_NODE == nexttype) { { switch (node.getNodeType()) { - case Node.DOCUMENT_FRAGMENT_NODE : - case Node.DOCUMENT_NODE : - case Node.ELEMENT_NODE : { - for (Node child = node.getFirstChild(); null != child; - child = child.getNextSibling()) { - dispatchNodeData(child, ch, depth + 1); - } - } - break; - case Node.PROCESSING_INSTRUCTION_NODE : // %REVIEW% - case Node.COMMENT_NODE : - if (0 != depth) { - break; - } - // NOTE: Because this operation works in the DOM space, it does _not_ attempt - // to perform Text Coalition. That should only be done in DTM space. - case Node.TEXT_NODE : - case Node.CDATA_SECTION_NODE : - case Node.ATTRIBUTE_NODE : - String str = node.getNodeValue(); - if (ch instanceof org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler) { - ((org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler)ch).characters(node); - } else { - ch.characters(str.toCharArray(), 0, str.length()); + case Node.DOCUMENT_FRAGMENT_NODE : + case Node.DOCUMENT_NODE : + case Node.ELEMENT_NODE : { + for (Node child = node.getFirstChild(); null != child; + child = child.getNextSibling()) { + dispatchNodeData(child, ch, depth + 1); + } } break; + case Node.PROCESSING_INSTRUCTION_NODE : // %REVIEW% + case Node.COMMENT_NODE : + if (0 != depth) { + break; + } + // NOTE: Because this operation works in the DOM space, it does _not_ attempt + // to perform Text Coalition. That should only be done in DTM space. + case Node.TEXT_NODE : + case Node.CDATA_SECTION_NODE : + case Node.ATTRIBUTE_NODE : + String str = node.getNodeValue(); + if (ch instanceof org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler) { + ((org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler)ch).characters(node); + } else { + ch.characters(str.toCharArray(), 0, str.length()); + } + break; // /* case Node.PROCESSING_INSTRUCTION_NODE : // // warning(XPATHErrorResources.WG_PARSING_AND_PREPARING); // break; */ - default : - // ignore - break; + default : + // ignore + break; } } diff --git a/ext/java/nokogiri/internals/dom2dtm/DOM2DTMdefaultNamespaceDeclarationNode.java b/ext/java/nokogiri/internals/dom2dtm/DOM2DTMdefaultNamespaceDeclarationNode.java index a2a720ab20..232deb653d 100644 --- a/ext/java/nokogiri/internals/dom2dtm/DOM2DTMdefaultNamespaceDeclarationNode.java +++ b/ext/java/nokogiri/internals/dom2dtm/DOM2DTMdefaultNamespaceDeclarationNode.java @@ -354,81 +354,81 @@ else if (!getBaseURI().equals(((NodeImpl) arg).getBaseURI())) { { short type = this.getNodeType(); switch (type) { - case Node.ELEMENT_NODE : { - - String namespace = this.getNamespaceURI(); - String prefix = this.getPrefix(); - if (namespace != null) { - // REVISIT: is it possible that prefix is empty string? - if (specifiedPrefix == null && prefix == specifiedPrefix) { - // looking for default namespace - return namespace; - } else if (prefix != null && prefix.equals(specifiedPrefix)) { - // non default namespace - return namespace; + case Node.ELEMENT_NODE : { + + String namespace = this.getNamespaceURI(); + String prefix = this.getPrefix(); + if (namespace != null) { + // REVISIT: is it possible that prefix is empty string? + if (specifiedPrefix == null && prefix == specifiedPrefix) { + // looking for default namespace + return namespace; + } else if (prefix != null && prefix.equals(specifiedPrefix)) { + // non default namespace + return namespace; + } } - } - if (this.hasAttributes()) { - NamedNodeMap map = this.getAttributes(); - int length = map.getLength(); - for (int i = 0; i < length; i++) { - Node attr = map.item(i); - String attrPrefix = attr.getPrefix(); - String value = attr.getNodeValue(); - namespace = attr.getNamespaceURI(); - if (namespace != null && namespace.equals("http://www.w3.org/2000/xmlns/")) { - // at this point we are dealing with DOM Level 2 nodes only - if (specifiedPrefix == null && - attr.getNodeName().equals("xmlns")) { - // default namespace - return value; - } else if (attrPrefix != null && - attrPrefix.equals("xmlns") && - attr.getLocalName().equals(specifiedPrefix)) { - // non default namespace - return value; + if (this.hasAttributes()) { + NamedNodeMap map = this.getAttributes(); + int length = map.getLength(); + for (int i = 0; i < length; i++) { + Node attr = map.item(i); + String attrPrefix = attr.getPrefix(); + String value = attr.getNodeValue(); + namespace = attr.getNamespaceURI(); + if (namespace != null && namespace.equals("http://www.w3.org/2000/xmlns/")) { + // at this point we are dealing with DOM Level 2 nodes only + if (specifiedPrefix == null && + attr.getNodeName().equals("xmlns")) { + // default namespace + return value; + } else if (attrPrefix != null && + attrPrefix.equals("xmlns") && + attr.getLocalName().equals(specifiedPrefix)) { + // non default namespace + return value; + } } } } - } - /* - NodeImpl ancestor = (NodeImpl)getElementAncestor(this); - if (ancestor != null) { - return ancestor.lookupNamespaceURI(specifiedPrefix); - } - */ + /* + NodeImpl ancestor = (NodeImpl)getElementAncestor(this); + if (ancestor != null) { + return ancestor.lookupNamespaceURI(specifiedPrefix); + } + */ - return null; + return null; - } - /* - case Node.DOCUMENT_NODE : { - return((NodeImpl)((Document)this).getDocumentElement()).lookupNamespaceURI(specifiedPrefix) ; - } - */ - case Node.ENTITY_NODE : - case Node.NOTATION_NODE: - case Node.DOCUMENT_FRAGMENT_NODE: - case Node.DOCUMENT_TYPE_NODE: - // type is unknown - return null; - case Node.ATTRIBUTE_NODE: { - if (this.getOwnerElement().getNodeType() == Node.ELEMENT_NODE) { - return getOwnerElement().lookupNamespaceURI(specifiedPrefix); - } - return null; - } - default: { /* - NodeImpl ancestor = (NodeImpl)getElementAncestor(this); - if (ancestor != null) { - return ancestor.lookupNamespaceURI(specifiedPrefix); - } - */ - return null; - } + case Node.DOCUMENT_NODE : { + return((NodeImpl)((Document)this).getDocumentElement()).lookupNamespaceURI(specifiedPrefix) ; + } + */ + case Node.ENTITY_NODE : + case Node.NOTATION_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + case Node.DOCUMENT_TYPE_NODE: + // type is unknown + return null; + case Node.ATTRIBUTE_NODE: { + if (this.getOwnerElement().getNodeType() == Node.ELEMENT_NODE) { + return getOwnerElement().lookupNamespaceURI(specifiedPrefix); + + } + return null; + } + default: { + /* + NodeImpl ancestor = (NodeImpl)getElementAncestor(this); + if (ancestor != null) { + return ancestor.lookupNamespaceURI(specifiedPrefix); + } + */ + return null; + } } } @@ -531,39 +531,39 @@ else if (!getBaseURI().equals(((NodeImpl) arg).getBaseURI())) { short type = this.getNodeType(); switch (type) { - /* - case Node.ELEMENT_NODE: { + /* + case Node.ELEMENT_NODE: { - String namespace = this.getNamespaceURI(); // to flip out children - return lookupNamespacePrefix(namespaceURI, (ElementImpl)this); - } + String namespace = this.getNamespaceURI(); // to flip out children + return lookupNamespacePrefix(namespaceURI, (ElementImpl)this); + } - case Node.DOCUMENT_NODE:{ - return((NodeImpl)((Document)this).getDocumentElement()).lookupPrefix(namespaceURI); - } - */ - case Node.ENTITY_NODE : - case Node.NOTATION_NODE: - case Node.DOCUMENT_FRAGMENT_NODE: - case Node.DOCUMENT_TYPE_NODE: - // type is unknown - return null; - case Node.ATTRIBUTE_NODE: { - if (this.getOwnerElement().getNodeType() == Node.ELEMENT_NODE) { - return getOwnerElement().lookupPrefix(namespaceURI); + case Node.DOCUMENT_NODE:{ + return((NodeImpl)((Document)this).getDocumentElement()).lookupPrefix(namespaceURI); + } + */ + case Node.ENTITY_NODE : + case Node.NOTATION_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + case Node.DOCUMENT_TYPE_NODE: + // type is unknown + return null; + case Node.ATTRIBUTE_NODE: { + if (this.getOwnerElement().getNodeType() == Node.ELEMENT_NODE) { + return getOwnerElement().lookupPrefix(namespaceURI); + } + return null; + } + default: { + /* + NodeImpl ancestor = (NodeImpl)getElementAncestor(this); + if (ancestor != null) { + return ancestor.lookupPrefix(namespaceURI); + } + */ + return null; } - return null; - } - default: { - /* - NodeImpl ancestor = (NodeImpl)getElementAncestor(this); - if (ancestor != null) { - return ancestor.lookupPrefix(namespaceURI); - } - */ - return null; - } } } diff --git a/ext/nokogiri/gumbo.c b/ext/nokogiri/gumbo.c index 7a3b42a878..269499153d 100644 --- a/ext/nokogiri/gumbo.c +++ b/ext/nokogiri/gumbo.c @@ -99,15 +99,15 @@ perform_parse(const GumboOptions *options, VALUE input) const char *status_string = gumbo_status_to_string(output->status); switch (output->status) { - case GUMBO_STATUS_OK: - break; - case GUMBO_STATUS_TOO_MANY_ATTRIBUTES: - case GUMBO_STATUS_TREE_TOO_DEEP: - gumbo_destroy_output(output); - rb_raise(rb_eArgError, "%s", status_string); - case GUMBO_STATUS_OUT_OF_MEMORY: - gumbo_destroy_output(output); - rb_raise(rb_eNoMemError, "%s", status_string); + case GUMBO_STATUS_OK: + break; + case GUMBO_STATUS_TOO_MANY_ATTRIBUTES: + case GUMBO_STATUS_TREE_TOO_DEEP: + gumbo_destroy_output(output); + rb_raise(rb_eArgError, "%s", status_string); + case GUMBO_STATUS_OUT_OF_MEMORY: + gumbo_destroy_output(output); + rb_raise(rb_eNoMemError, "%s", status_string); } return output; } @@ -176,82 +176,82 @@ build_tree( xmlNodePtr xml_child; switch (gumbo_child->type) { - case GUMBO_NODE_DOCUMENT: - abort(); // Bug in Gumbo. - - case GUMBO_NODE_TEXT: - case GUMBO_NODE_WHITESPACE: - xml_child = xmlNewDocText(doc, BAD_CAST gumbo_child->v.text.text); - set_line(xml_child, gumbo_child->v.text.start_pos.line); - xmlAddChild(xml_node, xml_child); - break; - - case GUMBO_NODE_CDATA: - xml_child = xmlNewCDataBlock(doc, BAD_CAST gumbo_child->v.text.text, - (int) strlen(gumbo_child->v.text.text)); - set_line(xml_child, gumbo_child->v.text.start_pos.line); - xmlAddChild(xml_node, xml_child); - break; - - case GUMBO_NODE_COMMENT: - xml_child = xmlNewDocComment(doc, BAD_CAST gumbo_child->v.text.text); - set_line(xml_child, gumbo_child->v.text.start_pos.line); - xmlAddChild(xml_node, xml_child); - break; - - case GUMBO_NODE_TEMPLATE: - // XXX: Should create a template element and a new DocumentFragment - case GUMBO_NODE_ELEMENT: { - xml_child = xmlNewDocNode(doc, NULL, BAD_CAST gumbo_child->v.element.name, NULL); - set_line(xml_child, gumbo_child->v.element.start_pos.line); - if (xml_root == NULL) { - xml_root = xml_child; - } - xmlNsPtr ns = NULL; - switch (gumbo_child->v.element.tag_namespace) { - case GUMBO_NAMESPACE_HTML: - break; - case GUMBO_NAMESPACE_SVG: - ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/2000/svg", "svg"); + case GUMBO_NODE_DOCUMENT: + abort(); // Bug in Gumbo. + + case GUMBO_NODE_TEXT: + case GUMBO_NODE_WHITESPACE: + xml_child = xmlNewDocText(doc, BAD_CAST gumbo_child->v.text.text); + set_line(xml_child, gumbo_child->v.text.start_pos.line); + xmlAddChild(xml_node, xml_child); break; - case GUMBO_NAMESPACE_MATHML: - ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/1998/Math/MathML", "math"); - break; - } - if (ns != NULL) { - xmlSetNs(xml_child, ns); - } - xmlAddChild(xml_node, xml_child); - - // Add the attributes. - const GumboVector *attrs = &gumbo_child->v.element.attributes; - for (size_t i = 0; i < attrs->length; i++) { - const GumboAttribute *attr = attrs->data[i]; - switch (attr->attr_namespace) { - case GUMBO_ATTR_NAMESPACE_XLINK: - ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/1999/xlink", "xlink"); - break; - - case GUMBO_ATTR_NAMESPACE_XML: - ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/XML/1998/namespace", "xml"); - break; + case GUMBO_NODE_CDATA: + xml_child = xmlNewCDataBlock(doc, BAD_CAST gumbo_child->v.text.text, + (int) strlen(gumbo_child->v.text.text)); + set_line(xml_child, gumbo_child->v.text.start_pos.line); + xmlAddChild(xml_node, xml_child); + break; - case GUMBO_ATTR_NAMESPACE_XMLNS: - ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/2000/xmlns/", "xmlns"); - break; + case GUMBO_NODE_COMMENT: + xml_child = xmlNewDocComment(doc, BAD_CAST gumbo_child->v.text.text); + set_line(xml_child, gumbo_child->v.text.start_pos.line); + xmlAddChild(xml_node, xml_child); + break; - default: - ns = NULL; + case GUMBO_NODE_TEMPLATE: + // XXX: Should create a template element and a new DocumentFragment + case GUMBO_NODE_ELEMENT: { + xml_child = xmlNewDocNode(doc, NULL, BAD_CAST gumbo_child->v.element.name, NULL); + set_line(xml_child, gumbo_child->v.element.start_pos.line); + if (xml_root == NULL) { + xml_root = xml_child; + } + xmlNsPtr ns = NULL; + switch (gumbo_child->v.element.tag_namespace) { + case GUMBO_NAMESPACE_HTML: + break; + case GUMBO_NAMESPACE_SVG: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/2000/svg", "svg"); + break; + case GUMBO_NAMESPACE_MATHML: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/1998/Math/MathML", "math"); + break; + } + if (ns != NULL) { + xmlSetNs(xml_child, ns); + } + xmlAddChild(xml_node, xml_child); + + // Add the attributes. + const GumboVector *attrs = &gumbo_child->v.element.attributes; + for (size_t i = 0; i < attrs->length; i++) { + const GumboAttribute *attr = attrs->data[i]; + + switch (attr->attr_namespace) { + case GUMBO_ATTR_NAMESPACE_XLINK: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/1999/xlink", "xlink"); + break; + + case GUMBO_ATTR_NAMESPACE_XML: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/XML/1998/namespace", "xml"); + break; + + case GUMBO_ATTR_NAMESPACE_XMLNS: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/2000/xmlns/", "xmlns"); + break; + + default: + ns = NULL; + } + xmlNewNsProp(xml_child, ns, BAD_CAST attr->name, BAD_CAST attr->value); } - xmlNewNsProp(xml_child, ns, BAD_CAST attr->name, BAD_CAST attr->value); - } - // Add children for this element. - child_index = 0; - gumbo_node = gumbo_child; - xml_node = xml_child; - } + // Add children for this element. + child_index = 0; + gumbo_node = gumbo_child; + xml_node = xml_child; + } } } } @@ -459,24 +459,24 @@ fragment( const char *colon = memchr(ctx_tag, ':', len); if (colon) { switch (colon - ctx_tag) { - case 3: - if (st_strncasecmp(ctx_tag, "svg", 3) != 0) { - goto error; - } - ctx_ns = GUMBO_NAMESPACE_SVG; - break; - case 4: - if (st_strncasecmp(ctx_tag, "html", 4) == 0) { - ctx_ns = GUMBO_NAMESPACE_HTML; - } else if (st_strncasecmp(ctx_tag, "math", 4) == 0) { - ctx_ns = GUMBO_NAMESPACE_MATHML; - } else { - goto error; - } - break; - default: + case 3: + if (st_strncasecmp(ctx_tag, "svg", 3) != 0) { + goto error; + } + ctx_ns = GUMBO_NAMESPACE_SVG; + break; + case 4: + if (st_strncasecmp(ctx_tag, "html", 4) == 0) { + ctx_ns = GUMBO_NAMESPACE_HTML; + } else if (st_strncasecmp(ctx_tag, "math", 4) == 0) { + ctx_ns = GUMBO_NAMESPACE_MATHML; + } else { + goto error; + } + break; + default: error: - rb_raise(rb_eArgError, "Invalid context namespace '%*s'", (int)(colon - ctx_tag), ctx_tag); + rb_raise(rb_eArgError, "Invalid context namespace '%*s'", (int)(colon - ctx_tag), ctx_tag); } ctx_tag = colon + 1; } else { diff --git a/ext/nokogiri/libxml2_backwards_compat.c b/ext/nokogiri/libxml2_backwards_compat.c index 2e084b9235..f5255cb989 100644 --- a/ext/nokogiri/libxml2_backwards_compat.c +++ b/ext/nokogiri/libxml2_backwards_compat.c @@ -20,14 +20,14 @@ xmlFirstElementChild(xmlNodePtr parent) return (NULL); } switch (parent->type) { - case XML_ELEMENT_NODE: - case XML_ENTITY_NODE: - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: - cur = parent->children; - break; - default: - return (NULL); + case XML_ELEMENT_NODE: + case XML_ENTITY_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + cur = parent->children; + break; + default: + return (NULL); } while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { @@ -57,20 +57,20 @@ xmlNextElementSibling(xmlNodePtr node) return (NULL); } switch (node->type) { - case XML_ELEMENT_NODE: - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_PI_NODE: - case XML_COMMENT_NODE: - case XML_DTD_NODE: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - node = node->next; - break; - default: - return (NULL); + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_DTD_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + node = node->next; + break; + default: + return (NULL); } while (node != NULL) { if (node->type == XML_ELEMENT_NODE) { @@ -101,14 +101,14 @@ xmlLastElementChild(xmlNodePtr parent) return (NULL); } switch (parent->type) { - case XML_ELEMENT_NODE: - case XML_ENTITY_NODE: - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: - cur = parent->last; - break; - default: - return (NULL); + case XML_ELEMENT_NODE: + case XML_ENTITY_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + cur = parent->last; + break; + default: + return (NULL); } while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { diff --git a/ext/nokogiri/xml_document.c b/ext/nokogiri/xml_document.c index c76842ef57..f90aa64a5f 100644 --- a/ext/nokogiri/xml_document.c +++ b/ext/nokogiri/xml_document.c @@ -6,19 +6,19 @@ static int dealloc_node_i2(xmlNodePtr key, xmlNodePtr node, xmlDocPtr doc) { switch (node->type) { - case XML_ATTRIBUTE_NODE: - xmlFreePropList((xmlAttrPtr)node); - break; - case XML_NAMESPACE_DECL: - xmlFreeNs((xmlNsPtr)node); - break; - case XML_DTD_NODE: - xmlFreeDtd((xmlDtdPtr)node); - break; - default: - if (node->parent == NULL) { - xmlAddChild((xmlNodePtr)doc, node); - } + case XML_ATTRIBUTE_NODE: + xmlFreePropList((xmlAttrPtr)node); + break; + case XML_NAMESPACE_DECL: + xmlFreeNs((xmlNsPtr)node); + break; + case XML_DTD_NODE: + xmlFreeDtd((xmlDtdPtr)node); + break; + default: + if (node->parent == NULL) { + xmlAddChild((xmlNodePtr)doc, node); + } } return ST_CONTINUE; } diff --git a/ext/nokogiri/xml_node.c b/ext/nokogiri/xml_node.c index 93e37c35a6..723ff72164 100644 --- a/ext/nokogiri/xml_node.c +++ b/ext/nokogiri/xml_node.c @@ -36,6 +36,7 @@ static void relink_namespace(xmlNodePtr reparented) { xmlNodePtr child; + xmlAttrPtr attr; if (reparented->type != XML_ATTRIBUTE_NODE && reparented->type != XML_ELEMENT_NODE) { return; } @@ -68,11 +69,6 @@ relink_namespace(xmlNodePtr reparented) /* Avoid segv when relinking against unlinked nodes. */ if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; } - /* Make sure that our reparented node has the correct namespaces */ - if (!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent) { - xmlSetNs(reparented, reparented->parent->ns); - } - /* Search our parents for an existing definition */ if (reparented->nsDef) { xmlNsPtr curr = reparented->nsDef; @@ -132,10 +128,10 @@ relink_namespace(xmlNodePtr reparented) } if (reparented->type == XML_ELEMENT_NODE) { - child = (xmlNodePtr)((xmlElementPtr)reparented)->attributes; - while (NULL != child) { - relink_namespace(child); - child = child->next; + attr = reparented->properties; + while (NULL != attr) { + relink_namespace((xmlNodePtr)attr); + attr = attr->next; } } } @@ -170,7 +166,7 @@ static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf) { VALUE reparented_obj ; - xmlNodePtr reparentee, pivot, reparented, next_text, new_next_text, parent ; + xmlNodePtr reparentee, original_reparentee, pivot, reparented, next_text, new_next_text, parent ; int original_ns_prefix_is_default = 0 ; if (!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) { @@ -197,66 +193,66 @@ reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func if (parent) { switch (parent->type) { - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: - switch (reparentee->type) { - case XML_ELEMENT_NODE: - case XML_PI_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - /* - * The DOM specification says no to adding text-like nodes - * directly to a document, but we allow it for compatibility. - */ - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_ENTITY_REF_NODE: - goto ok; - default: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + switch (reparentee->type) { + case XML_ELEMENT_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + /* + * The DOM specification says no to adding text-like nodes + * directly to a document, but we allow it for compatibility. + */ + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + goto ok; + default: + break; + } break; - } - break; - case XML_DOCUMENT_FRAG_NODE: - case XML_ENTITY_REF_NODE: - case XML_ELEMENT_NODE: - switch (reparentee->type) { - case XML_ELEMENT_NODE: - case XML_PI_NODE: - case XML_COMMENT_NODE: - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: + case XML_DOCUMENT_FRAG_NODE: case XML_ENTITY_REF_NODE: - goto ok; - default: + case XML_ELEMENT_NODE: + switch (reparentee->type) { + case XML_ELEMENT_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + goto ok; + default: + break; + } + break; + case XML_ATTRIBUTE_NODE: + switch (reparentee->type) { + case XML_TEXT_NODE: + case XML_ENTITY_REF_NODE: + goto ok; + default: + break; + } break; - } - break; - case XML_ATTRIBUTE_NODE: - switch (reparentee->type) { case XML_TEXT_NODE: - case XML_ENTITY_REF_NODE: - goto ok; + /* + * xmlAddChild() breaks the DOM specification in that it allows + * adding a text node to another, in which case text nodes are + * coalesced, but since our JRuby version does not support such + * operation, we should inhibit it. + */ + break; default: break; - } - break; - case XML_TEXT_NODE: - /* - * xmlAddChild() breaks the DOM specification in that it allows - * adding a text node to another, in which case text nodes are - * coalesced, but since our JRuby version does not support such - * operation, we should inhibit it. - */ - break; - default: - break; } rb_raise(rb_eArgError, "cannot reparent %s there", rb_obj_classname(reparentee_obj)); } ok: - xmlUnlinkNode(reparentee); + original_reparentee = reparentee; if (reparentee->doc != pivot->doc || reparentee->type == XML_TEXT_NODE) { /* @@ -313,6 +309,8 @@ reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func } } + xmlUnlinkNode(original_reparentee); + if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling && reparentee->type == XML_TEXT_NODE && pivot->next && pivot->next->type == XML_TEXT_NODE) { /* @@ -1633,12 +1631,12 @@ in_context(VALUE self, VALUE _str, VALUE _options) /* FIXME: This probably needs to handle more constants... */ switch (error) { - case XML_ERR_INTERNAL_ERROR: - case XML_ERR_NO_MEMORY: - rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error); - break; - default: - break; + case XML_ERR_INTERNAL_ERROR: + case XML_ERR_NO_MEMORY: + rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error); + break; + default: + break; } set = xmlXPathNodeSetCreate(NULL); @@ -1682,44 +1680,44 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node) if (!RTEST(rb_class)) { switch (c_node->type) { - case XML_ELEMENT_NODE: - rb_class = cNokogiriXmlElement; - break; - case XML_TEXT_NODE: - rb_class = cNokogiriXmlText; - break; - case XML_ATTRIBUTE_NODE: - rb_class = cNokogiriXmlAttr; - break; - case XML_ENTITY_REF_NODE: - rb_class = cNokogiriXmlEntityReference; - break; - case XML_COMMENT_NODE: - rb_class = cNokogiriXmlComment; - break; - case XML_DOCUMENT_FRAG_NODE: - rb_class = cNokogiriXmlDocumentFragment; - break; - case XML_PI_NODE: - rb_class = cNokogiriXmlProcessingInstruction; - break; - case XML_ENTITY_DECL: - rb_class = cNokogiriXmlEntityDecl; - break; - case XML_CDATA_SECTION_NODE: - rb_class = cNokogiriXmlCData; - break; - case XML_DTD_NODE: - rb_class = cNokogiriXmlDtd; - break; - case XML_ATTRIBUTE_DECL: - rb_class = cNokogiriXmlAttributeDecl; - break; - case XML_ELEMENT_DECL: - rb_class = cNokogiriXmlElementDecl; - break; - default: - rb_class = cNokogiriXmlNode; + case XML_ELEMENT_NODE: + rb_class = cNokogiriXmlElement; + break; + case XML_TEXT_NODE: + rb_class = cNokogiriXmlText; + break; + case XML_ATTRIBUTE_NODE: + rb_class = cNokogiriXmlAttr; + break; + case XML_ENTITY_REF_NODE: + rb_class = cNokogiriXmlEntityReference; + break; + case XML_COMMENT_NODE: + rb_class = cNokogiriXmlComment; + break; + case XML_DOCUMENT_FRAG_NODE: + rb_class = cNokogiriXmlDocumentFragment; + break; + case XML_PI_NODE: + rb_class = cNokogiriXmlProcessingInstruction; + break; + case XML_ENTITY_DECL: + rb_class = cNokogiriXmlEntityDecl; + break; + case XML_CDATA_SECTION_NODE: + rb_class = cNokogiriXmlCData; + break; + case XML_DTD_NODE: + rb_class = cNokogiriXmlDtd; + break; + case XML_ATTRIBUTE_DECL: + rb_class = cNokogiriXmlAttributeDecl; + break; + case XML_ELEMENT_DECL: + rb_class = cNokogiriXmlElementDecl; + break; + default: + rb_class = cNokogiriXmlNode; } } diff --git a/ext/nokogiri/xml_node_set.c b/ext/nokogiri/xml_node_set.c index 1c17c2affd..5670371a93 100644 --- a/ext/nokogiri/xml_node_set.c +++ b/ext/nokogiri/xml_node_set.c @@ -20,20 +20,20 @@ ruby_object_get(xmlNodePtr c_node) { /* see xmlElementType in libxml2 tree.h */ switch (c_node->type) { - case XML_NAMESPACE_DECL: - /* _private is later in the namespace struct */ - return (VALUE)(((xmlNsPtr)c_node)->_private); - - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: - /* in documents we use _private to store a tuple */ - if (DOC_RUBY_OBJECT_TEST(((xmlDocPtr)c_node))) { - return DOC_RUBY_OBJECT((xmlDocPtr)c_node); - } - return (VALUE)NULL; - - default: - return (VALUE)(c_node->_private); + case XML_NAMESPACE_DECL: + /* _private is later in the namespace struct */ + return (VALUE)(((xmlNsPtr)c_node)->_private); + + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + /* in documents we use _private to store a tuple */ + if (DOC_RUBY_OBJECT_TEST(((xmlDocPtr)c_node))) { + return DOC_RUBY_OBJECT((xmlDocPtr)c_node); + } + return (VALUE)NULL; + + default: + return (VALUE)(c_node->_private); } } @@ -373,12 +373,12 @@ slice(int argc, VALUE *argv, VALUE self) /* if arg is Range */ switch (rb_range_beg_len(arg, &beg, &len, (long)node_set->nodeNr, 0)) { - case Qfalse: - break; - case Qnil: - return Qnil; - default: - return subseq(self, beg, len); + case Qfalse: + break; + case Qnil: + return Qnil; + default: + return subseq(self, beg, len); } return index_at(self, NUM2LONG(arg)); diff --git a/ext/nokogiri/xml_sax_parser.c b/ext/nokogiri/xml_sax_parser.c index 1e4a293ff0..5d953be6c2 100644 --- a/ext/nokogiri/xml_sax_parser.c +++ b/ext/nokogiri/xml_sax_parser.c @@ -30,12 +30,12 @@ start_document(void *ctx) version = ctxt->version ? NOKOGIRI_STR_NEW2(ctxt->version) : Qnil; switch (ctxt->standalone) { - case 0: - standalone = NOKOGIRI_STR_NEW2("no"); - break; - case 1: - standalone = NOKOGIRI_STR_NEW2("yes"); - break; + case 0: + standalone = NOKOGIRI_STR_NEW2("no"); + break; + case 1: + standalone = NOKOGIRI_STR_NEW2("yes"); + break; } rb_funcall(doc, id_xmldecl, 3, version, encoding, standalone); diff --git a/ext/nokogiri/xml_xpath_context.c b/ext/nokogiri/xml_xpath_context.c index 805b1dd507..c148d1c28b 100644 --- a/ext/nokogiri/xml_xpath_context.c +++ b/ext/nokogiri/xml_xpath_context.c @@ -154,20 +154,20 @@ Nokogiri_marshal_xpath_funcall_and_return_values(xmlXPathParserContextPtr ctx, i do { obj = valuePop(ctx); switch (obj->type) { - case XPATH_STRING: - argv[i] = NOKOGIRI_STR_NEW2(obj->stringval); - break; - case XPATH_BOOLEAN: - argv[i] = obj->boolval == 1 ? Qtrue : Qfalse; - break; - case XPATH_NUMBER: - argv[i] = rb_float_new(obj->floatval); - break; - case XPATH_NODESET: - argv[i] = noko_xml_node_set_wrap(obj->nodesetval, doc); - break; - default: - argv[i] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(obj)); + case XPATH_STRING: + argv[i] = NOKOGIRI_STR_NEW2(obj->stringval); + break; + case XPATH_BOOLEAN: + argv[i] = obj->boolval == 1 ? Qtrue : Qfalse; + break; + case XPATH_NUMBER: + argv[i] = rb_float_new(obj->floatval); + break; + case XPATH_NODESET: + argv[i] = noko_xml_node_set_wrap(obj->nodesetval, doc); + break; + default: + argv[i] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(obj)); } xmlXPathFreeNodeSetList(obj); } while (i-- > 0); @@ -181,43 +181,43 @@ Nokogiri_marshal_xpath_funcall_and_return_values(xmlXPathParserContextPtr ctx, i free(argv); switch (TYPE(result)) { - case T_FLOAT: - case T_BIGNUM: - case T_FIXNUM: - xmlXPathReturnNumber(ctx, NUM2DBL(result)); - break; - case T_STRING: - xmlXPathReturnString( - ctx, - xmlCharStrdup(StringValueCStr(result)) - ); - break; - case T_TRUE: - xmlXPathReturnTrue(ctx); - break; - case T_FALSE: - xmlXPathReturnFalse(ctx); - break; - case T_NIL: - break; - case T_ARRAY: { - VALUE args[2]; - args[0] = doc; - args[1] = result; - node_set = rb_class_new_instance(2, args, cNokogiriXmlNodeSet); - Data_Get_Struct(node_set, xmlNodeSet, xml_node_set); - xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set)); - } - break; - case T_DATA: - if (rb_obj_is_kind_of(result, cNokogiriXmlNodeSet)) { - Data_Get_Struct(result, xmlNodeSet, xml_node_set); - /* Copy the node set, otherwise it will get GC'd. */ - xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set)); + case T_FLOAT: + case T_BIGNUM: + case T_FIXNUM: + xmlXPathReturnNumber(ctx, NUM2DBL(result)); + break; + case T_STRING: + xmlXPathReturnString( + ctx, + xmlCharStrdup(StringValueCStr(result)) + ); + break; + case T_TRUE: + xmlXPathReturnTrue(ctx); + break; + case T_FALSE: + xmlXPathReturnFalse(ctx); break; + case T_NIL: + break; + case T_ARRAY: { + VALUE args[2]; + args[0] = doc; + args[1] = result; + node_set = rb_class_new_instance(2, args, cNokogiriXmlNodeSet); + Data_Get_Struct(node_set, xmlNodeSet, xml_node_set); + xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set)); } - default: - rb_raise(rb_eRuntimeError, "Invalid return type"); + break; + case T_DATA: + if (rb_obj_is_kind_of(result, cNokogiriXmlNodeSet)) { + Data_Get_Struct(result, xmlNodeSet, xml_node_set); + /* Copy the node set, otherwise it will get GC'd. */ + xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set)); + break; + } + default: + rb_raise(rb_eRuntimeError, "Invalid return type"); } } @@ -314,22 +314,22 @@ evaluate(int argc, VALUE *argv, VALUE self) assert(DOC_RUBY_OBJECT_TEST(ctx->doc)); switch (xpath->type) { - case XPATH_STRING: - thing = NOKOGIRI_STR_NEW2(xpath->stringval); - xmlFree(xpath->stringval); - break; - case XPATH_NODESET: - thing = noko_xml_node_set_wrap(xpath->nodesetval, - DOC_RUBY_OBJECT(ctx->doc)); - break; - case XPATH_NUMBER: - thing = rb_float_new(xpath->floatval); - break; - case XPATH_BOOLEAN: - thing = xpath->boolval == 1 ? Qtrue : Qfalse; - break; - default: - thing = noko_xml_node_set_wrap(NULL, DOC_RUBY_OBJECT(ctx->doc)); + case XPATH_STRING: + thing = NOKOGIRI_STR_NEW2(xpath->stringval); + xmlFree(xpath->stringval); + break; + case XPATH_NODESET: + thing = noko_xml_node_set_wrap(xpath->nodesetval, + DOC_RUBY_OBJECT(ctx->doc)); + break; + case XPATH_NUMBER: + thing = rb_float_new(xpath->floatval); + break; + case XPATH_BOOLEAN: + thing = xpath->boolval == 1 ? Qtrue : Qfalse; + break; + default: + thing = noko_xml_node_set_wrap(NULL, DOC_RUBY_OBJECT(ctx->doc)); } xmlXPathFreeNodeSetList(xpath); diff --git a/rakelib/format.rake b/rakelib/format.rake index 9413365527..306227c5a5 100644 --- a/rakelib/format.rake +++ b/rakelib/format.rake @@ -13,6 +13,7 @@ namespace "format" do [ # indentation "--indent=spaces=2", + "--indent-switches", # brackets "--style=1tbs", diff --git a/test/namespaces/test_namespaces_in_created_doc.rb b/test/namespaces/test_namespaces_in_created_doc.rb index 43dd7a9b8b..a1cc701ad1 100644 --- a/test/namespaces/test_namespaces_in_created_doc.rb +++ b/test/namespaces/test_namespaces_in_created_doc.rb @@ -7,7 +7,7 @@ def setup super @doc = Nokogiri::XML('') pear = @doc.create_element('pear') - bosc = @doc.create_element('bosc') + bosc = @doc.create_element('bosc', {"veg:any" => "none"}) pear.add_child(bosc) @doc.root << pear @doc.root.add_child('') @@ -38,6 +38,9 @@ def test_created_parent_default_ns def test_created_grandparent_default_ns assert_equal 'ns:fruit', check_namespace(@doc.root.elements[0].elements[0]) end + def test_created_attribute_with_ns + assert_equal 'ns:veg', check_namespace(@doc.root.elements[0].elements[0].attribute_nodes.first) + end def test_created_parent_nondefault_ns assert_equal 'ns:veg', check_namespace(@doc.root.elements[2]) end diff --git a/test/xml/test_node_reparenting.rb b/test/xml/test_node_reparenting.rb index 2bd80cf9f0..77fc1ebe42 100644 --- a/test/xml/test_node_reparenting.rb +++ b/test/xml/test_node_reparenting.rb @@ -360,6 +360,30 @@ def coerce(data) assert_match(%r{}, @doc.to_xml) end end + + describe "and a child node has a namespaced attribute" do + # https://github.com/sparklemotion/nokogiri/issues/2228 + it "should not lose attribute namespace" do + source_doc = Nokogiri::XML::Document.parse(<<~EOXML) + + + + EOXML + assert(source_node = source_doc.at_xpath("//pre1:child", {"pre1" => "ns1"})) + assert_equal("attrval", source_node.attribute_with_ns("attr", "ns2")&.value) + + dest_doc = Nokogiri::XML::Document.parse(<<~EOXML) + + + EOXML + assert(dest_node = dest_doc.at_xpath("//pre1:root", {"pre1" => "ns1"})) + + inserted = dest_node.add_child(source_node) + + assert_equal("attrval", inserted.attribute_with_ns("attr", "ns2")&.value, + "inserted node attribute should be namespaced") + end + end end describe "given a parent node with a default and non-default namespace" do