diff --git a/ext/java/nokogiri/XsltStylesheet.java b/ext/java/nokogiri/XsltStylesheet.java index d35ee8ff91..d343718470 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, org.apache.xml.serializer.Method.UNKNOWN); + 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) diff --git a/test/xslt/test_xml_header.rb b/test/xslt/test_xml_header.rb new file mode 100644 index 0000000000..2681f7ef77 --- /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