有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用SAXTransformerFactory和TransformerHandler访问XSLT中未解析的实体

使用XPath函数unparsed-entity-uri()检索未解析的实体URI时遇到一些问题

我使用的是类似于"Efficient XSLT pipeline in Java" question中的SAXTransformerFactory,因为我需要执行一个转换链(即应用几个XSLT转换,并使用转换的结果作为第二个转换的输入)

由于下面的代码,我发现我无法检索未解析的实体事实上,它在Xalan上运行良好,但在Saxon HE(9.7.0版)上运行不好——但我需要Saxon,因为我更喜欢XSLT 2.0(即使在下面的代码中没有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中,我有(对于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>

但是<cover>在使用Saxon执行转换时是空的


共 (2) 个答案

  1. # 1 楼答案

    事实上,按照@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));
    

    (最初使用的)

  2. # 2 楼答案

    有趣的观察。事实上,问题不在于Saxon的TransformerHandler,而在于使用SAXTransformerFactory获得的“身份转换器”。newTransformer():标识转换器未沿线路传递未解析的实体。这基本上是因为Saxon的identity transformer正在重用XSLT引擎的一部分,而XSLT并没有提供任何转换方法来输出结果中未解析的实体。如果您将SAX解析器输出直接发送到TransformerHandler,而不是通过标识转换器,那么我认为这一切都可以工作

    与所有与JAXP相关的内容一样,SAXTransformerFactory的规范也与JAXP相关。newTransformer()含糊不清,令人恼火。它所说的只是返回的Transformer将源代码复制到结果中。i、 e.“身份转换”。什么才算是副本?我认为Saxon的解释是,它相当于执行XSLT标识转换的效果——这将丢失未解析的实体(以及其他内容,如CDATA部分、DTD等)

    顺便说一句,XSLT 2.0指定unparsed-entity-uri()的结果应该是绝对uri(XSLT 1.0没有对该主题做任何说明),因此即使这是固定的,Saxon输出也会有所不同

    这里作为一个Saxon问题输入:https://saxonica.plan.io/issues/3201我认为,如果我们没有传递SAX DTDHandler所期望的所有其他事件,那么在将未解析的实体传递给SAXResult时,我们需要稍微小心一点——而且我们肯定不会更改Saxon标识转换器来保留XDM中未建模的东西(如DTD声明)