我一直在四处寻找Java样本来使用XSLT转换XML文档。我发现了几个使用new File("path/to/file.xml")
加载XML和XSLT的示例,这些示例效果很好。我的问题是我试图在一个接受两个org.w3c.dom.Document
对象的新方法中使用它。一旦用StreamSource
替换用于加载XSLT的DOMSource
,我的调用结果就是XSLT而不是转换后的XML。
来自How to call XSL template from java code?的工作代码:
Source xmlInput = new StreamSource(new File("c:/path/to/input.xml"));
Source xsl = new StreamSource(new File("c:/path/to/file.xsl"));
Result xmlOutput = new StreamResult(new File("c:/path/to/output.xml"));
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer(xsl);
transformer.transform(xmlInput, xmlOutput);
} catch (TransformerException e) {
// Handle.
}
我的代码:
public static Document transformXML(Document xml, Document xslt) throws TransformerException, UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException, FactoryConfigurationError{
Source xmlSource = new DOMSource(xml);
Source xsltSource = new DOMSource(xslt);
StreamResult result = new StreamResult(new StringWriter());
// the factory pattern supports different XSLT processors
TransformerFactory transFact =
TransformerFactory.newInstance();
Transformer trans = transFact.newTransformer(xsltSource);
trans.transform(xmlSource, result);
Document resultDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(result.getWriter().toString().getBytes("utf-8")));
return resultDoc;
}
我的结果文档是XSLT而不是XML。我对DOMSource
的错误是什么?
答案 0 :(得分:0)
XSLT和XPath只对名称空间感知的DOM实现和DOM树有意义,这就是为什么我要问"您使用名称空间感知文档构建器构建的变换器的DOM树是什么?"在我的评论中。
就我使用Oracle Java 1.8进行测试时,如果使用了不支持命名空间的DocumentBuilderFactory
和内置的Transformer
,则您的方法将返回样式表代码。但是,只要我将DocumentBuilderFactory
更改为可识别名称空间,结果就是预期的结果。
以下是工作样本:
package domsourcetest1;
import java.io.IOException;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.SAXException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
/**
*
* @author Martin Honnen
*/
public class DOMSourceTest1 {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, TransformerException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document xslt = db.parse("sheet1.xsl");
Document xml = db.newDocument();
xml.appendChild(xml.createElementNS(null, "root"));
Document result = transformXML(xml, xslt);
System.out.println(result.getDocumentElement().getTextContent());
LSSerializer serializer = ((DOMImplementationLS) xml.getImplementation()).createLSSerializer();
System.out.println(serializer.writeToString(result));
}
public static Document transformXML(Document xml, Document xslt) throws TransformerException, ParserConfigurationException, FactoryConfigurationError {
Source xmlSource = new DOMSource(xml);
Source xsltSource = new DOMSource(xslt);
DOMResult result = new DOMResult();
// the factory pattern supports different XSLT processors
TransformerFactory transFact
= TransformerFactory.newInstance();
Transformer trans = transFact.newTransformer(xsltSource);
trans.transform(xmlSource, result);
Document resultDoc = (Document) result.getNode();
return resultDoc;
}
}
示例样式表只输出有关XSLT处理器的信息:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<debug>
<xsl:value-of select="system-property('xsl:vendor')"/>
</debug>
</xsl:template>
</xsl:stylesheet>
该计划的输出是
Apache Software Foundation (Xalan XSLTC)
<?xml version="1.0" encoding="UTF-16"?>
<debug>Apache Software Foundation (Xalan XSLTC)</debug>
现在,当我在//dbf.setNamespaceAware(true);
方法中注释main
时结果为
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><debug><xsl:value-of select="system-property('xsl:vendor')"/></debug></xsl:template></xsl:stylesheet>
意味着结果确实是样式表文档。这显然是一个错误,或者至少是内置Xalan Transformer的怪癖,当我把Saxon 6.5.5放在类路径上时,问题不会发生,类路径上的Saxon 9.6也不会发生。
但是,一般情况下,当使用XSLT或XPath而不是名称空间感知的DOM树时,我认为您不会得到有意义的结果。另请参阅Xalan版本http://svn.apache.org/viewvc/xalan/java/tags/xalan-j_2_7_2/samples/DOM2DOM/DOM2DOM.java?revision=1695338&view=markup中的DOM2DOM示例,其中包含
// And setNamespaceAware, which is required when parsing xsl files
dFactory.setNamespaceAware(true);