使用XPath函数unparsed-entity-uri()
检索未解析的实体URI时遇到了一些问题。
我在"Efficient XSLT pipeline in Java" question中使用SAXTransformerFactory
,因为我需要执行转换链(即应用多个XSLT转换,并使用转换结果作为第二个输入变换)。
我发现我无法检索未解析的实体,感谢下面的代码。 实际上它适用于Xalan,但不适用于Saxon-HE(版本9.7.0) - 但我需要撒克逊,因为我更喜欢XSLT 2.0(即使在下面的代码中&#39 ;没有什么特别针对XSLT 2,它只是为了提供一个例子)。如果我不使用TransformerHandler,它也适用于Saxon,例如: stf.newTransformer(new StreamSource("transfo.xsl")).transform(new StreamSource("input.xsl"), new StreamResult(System.out))
将产生所需的输出。
我忘记了配置步骤吗?
// use "org.apache.xalan.processor.TransformerFactoryImpl" for Xalan
String transformerFactoryClassName = "net.sf.saxon.TransformerFactoryImpl";
SAXTransformerFactory stf = (SAXTransformerFactory) TransformerFactory.newInstance(transformerFactoryClassName,
LaunchSimpleTransformationUnparsedEntities.class.getClassLoader());
try {
TransformerHandler thTransf = stf
.newTransformerHandler(new StreamSource("transfo.xsl"));
// output the result in console
thTransf.setResult(new StreamResult(System.out));
// Launch transformation of input.xml
Transformer t = stf.newTransformer();
t.transform(new StreamSource("input.xml"),
new SAXResult(thTransf));
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
在输入中,我有(对于input.xml):
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE book
[<!ENTITY cover_hadrien SYSTEM "images/covers/cover_hadrien.jpg" NDATA jpeg>]>
<book>
<title>Les mémoires d'Hadrien</title>
<author>Marguerite Yourcenar</author>
<cover imgref="cover_hadrien" />
</book>
和示例XSLT(对于transfo.xsl):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="cover">
<xsl:copy>
<xsl:value-of select="unparsed-entity-uri(@imgref)"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
因此,我希望有类似的东西:
<?xml version="1.0" encoding="UTF-8"?><book>
<title>Les mémoires d'Hadrien</title>
<author>Marguerite Yourcenar</author>
<cover>images/covers/cover_hadrien.jpg</cover>
</book>
但使用Saxon执行转换时<cover>
为空。
答案 0 :(得分:1)
有趣的观察。实际上问题不在于Saxon的TransformerHandler,而在于使用SAXTransformerFactory.newTransformer()获得的“身份变换器”:身份变换器不会将未解析的实体传递给线路。这主要是因为Saxon的身份转换器正在重用XSLT引擎的一部分,而XSLT没有提供任何转换方式来输出结果中未解析的实体。如果您将SAX解析器输出直接发送到TransformerHandler,而不是通过身份转换器,那么我认为它都可以工作。
与JAXP相关的所有事情一样,SAXTransformerFactory.newTransformer()的规范令人愤慨地含糊不清。它说的是返回的Transformer 执行Source到Result的副本。即“身份变换”。究竟什么是副本?我认为Saxon的解释是它相当于进行XSLT身份转换的效果 - 它会丢失未解析的实体(以及其他东西,如CDATA部分,DTD等)。
顺便提一下,XSLT 2.0指定unparsed-entity-uri()的结果应该是绝对URI(XSLT 1.0没有说明任何内容),所以即使修复了这个问题,Saxon输出也会不同。 / p>
在这里作为Saxon问题输入:https://saxonica.plan.io/issues/3201如果我们不传递SAX DTDHandler所期望的所有其他事件,我认为我们需要小心将未解析的实体传递给SAXResult - 我们'肯定不会改变Saxon身份变换器以保留未在XDM中建模的东西(如DTD声明)。
答案 1 :(得分:0)
确实,按照@ MichaelKay的详细信息,以正确的方式启动转换:
// launch transformation of input.xml
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setContentHandler(thTransf);
reader.setDTDHandler(thTransf);
reader.parse(new InputSource(input.xml"));
(这将取代以下行:
// Launch transformation of input.xml
Transformer t = stf.newTransformer();
t.transform(new StreamSource("input.xml"),
new SAXResult(thTransf));
最初使用的。