From 9c266463ba762bab2aa25fd681450099bf785cd7 Mon Sep 17 00:00:00 2001 From: cbasguti Date: Sat, 10 Jun 2023 15:28:12 +0200 Subject: [PATCH 1/2] dev: avoid incorrectly including xml header in xslt output --- ext/java/nokogiri/XsltStylesheet.java | 2 +- test/xslt/test_xml_header.rb | 50 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/xslt/test_xml_header.rb diff --git a/ext/java/nokogiri/XsltStylesheet.java b/ext/java/nokogiri/XsltStylesheet.java index d35ee8ff91c..5565446adff 100644 --- a/ext/java/nokogiri/XsltStylesheet.java +++ b/ext/java/nokogiri/XsltStylesheet.java @@ -185,7 +185,7 @@ public class XsltStylesheet extends RubyObject java.util.Properties props = this.sheet.getOutputProperties(); if (props.getProperty(OutputKeys.METHOD) == null) { - props.setProperty(OutputKeys.METHOD, org.apache.xml.serializer.Method.UNKNOWN); + props.setProperty(OutputKeys.METHOD, "html"); } Serializer serializer = SerializerFactory.getSerializer(props); diff --git a/test/xslt/test_xml_header.rb b/test/xslt/test_xml_header.rb new file mode 100644 index 00000000000..2681f7ef77f --- /dev/null +++ b/test/xslt/test_xml_header.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require "minitest/autorun" +require "nokogiri" + +class OutputTest < Minitest::Test + def test_output + input_xml = <<~XML + + + My Report + + XML + + input_xsl = <<~XSL + + + + + + <xsl:value-of select="report/title"/> + + +

+ + +
+
+ XSL + + expected_output = <<~HTML + + + + My Report + +

My Report

+ + HTML + + xml = Nokogiri::XML(input_xml) + xsl = Nokogiri::XSLT(input_xsl) + actual_output = xsl.apply_to(xml) + + expected_output_normalized = expected_output.gsub(/\s+/, "").downcase + actual_output_normalized = actual_output.gsub(/\s+/, "").downcase + + assert_equal(expected_output_normalized, actual_output_normalized) + end +end From 879dc32a5b3d11b11d6735d5cb7a9c1e6dee9c2a Mon Sep 17 00:00:00 2001 From: cbasguti Date: Sun, 11 Jun 2023 10:00:41 +0200 Subject: [PATCH 2/2] dev: default method determination in serialize function --- ext/java/nokogiri/XsltStylesheet.java | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ext/java/nokogiri/XsltStylesheet.java b/ext/java/nokogiri/XsltStylesheet.java index 5565446adff..d3437184700 100644 --- a/ext/java/nokogiri/XsltStylesheet.java +++ b/ext/java/nokogiri/XsltStylesheet.java @@ -40,6 +40,7 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.w3c.dom.Document; +import org.w3c.dom.Node; import nokogiri.internals.NokogiriXsltErrorListener; @@ -185,7 +186,23 @@ public class XsltStylesheet extends RubyObject java.util.Properties props = this.sheet.getOutputProperties(); if (props.getProperty(OutputKeys.METHOD) == null) { - props.setProperty(OutputKeys.METHOD, "html"); + Node rootNode = xmlDoc.getNode().getFirstChild(); + + if (rootNode != null && rootNode.getNodeType() == Node.ELEMENT_NODE) { + String firstChildLocalName = rootNode.getLocalName(); + + if (firstChildLocalName.equalsIgnoreCase("html") && rootNode.getNamespaceURI() == null) { + Node textNode = rootNode.getPreviousSibling(); + + if (textNode == null || (textNode.getNodeType() == Node.TEXT_NODE && textNode.getTextContent().trim().isEmpty())) { + props.setProperty(OutputKeys.METHOD, "html"); + } + } + } + + if (props.getProperty(OutputKeys.METHOD) == null) { + props.setProperty(OutputKeys.METHOD, "xml"); + } } Serializer serializer = SerializerFactory.getSerializer(props); @@ -195,6 +212,7 @@ public class XsltStylesheet extends RubyObject return context.getRuntime().newString(writer.toString()); } + @JRubyMethod(rest = true, required = 1, optional = 2) public IRubyObject transform(ThreadContext context, IRubyObject[] args)