【问题标题】:XSL transformation then XPath expression on resulting nodeXSL 转换,然后是结果节点上的 XPath 表达式
【发布时间】:2012-07-23 14:28:03
【问题描述】:

我正在对输入 XML 进行 XSL 转换,然后我需要在结果文档上使用 XPath 提取一些值。但是在使用 XSL 结果节点时,XPath 表达式可能总是返回 null。 但是如果我将 XSL 生成的文档存储在一个文件中,然后重新加载它。 XPath 表达式返回对应的节点。

这是我的代码(实用功能已被删除):

public class XmlTest {
@Test
public void testWithNativeJavaApi() throws Exception {
    InputStream instream = resolveClasspathFile("xslt/xslt-test-transform-2.xsl");
    StreamSource xsltSource = new StreamSource(instream);
    DOMSource domSource = loadXmlFromClasspathFile("xslt/xslt-test-input-2.xml");
    prettyPrint(domSource.getNode());

    Transformer transformer = TransformerFactory.newInstance().newTransformer(xsltSource);
    DOMResult domResult = new DOMResult();
    transformer.transform(domSource, domResult);
    Node node = domResult.getNode();

    // Store then reload the file
    // Uncommenting those 3 lines will make the test pass
    // File xslOutputfile = new File("target", "xsl-ouput.xml");
    // prettyPrint(node, new FileOutputStream(xslOutputfile));
    // node = loadXmlFromInputStream(new FileInputStream(xslOutputfile)).getNode();

    XPath xPathProcessor = XPathFactory.newInstance().newXPath();
    XPathExpression xpathExpression = xPathProcessor.compile("/Message/Out/Personne/CodeCivilite");
    System.out.println();
    Node resultNode = (Node) xpathExpression.evaluate(node, XPathConstants.NODE);

    if (resultNode != null) {
        System.out.println(resultNode.getNodeName() + "=" + resultNode.getTextContent());
    } else {
        System.out.println("Node is null");
    }

    assertNotNull("XPath expression returned null node", resultNode);
    assertEquals("CodeCivilite", resultNode.getNodeName());
    assertEquals("M.", resultNode.getTextContent());

}
}

只需注释或删除“// Store then reload the file”下面的3行,测试将不再通过。

我完全陷入困境,欢迎任何帮助。

【问题讨论】:

    标签: java xml xslt xpath


    【解决方案1】:

    DocumentBuilderFactory 默认不使用命名空间,除非使用 dbf.setNamespaceAware(true)。另一方面,XSL 和 TransformerFactory 大量使用命名空间,因此转换的结果文档使用命名空间限定。

    因此,在 XSL 转换旁边调用 XPathExpression 时应该使用命名空间。

    XPath xPathProcessor = XPathFactory.newInstance().newXPath();
    xPathProcessor.setNamespaceContext(new NamespaceContext() {
      @Override
      public String getNamespaceURI(String prefix) {
        if(prefix.equals("t")) {
          return "http://www.example.org/test";
        } else {
          return null;  
        }
      }
      @Override public String getPrefix(String namespaceURI) {
        return null; // not used
      }
      @Override
      public Iterator<?> getPrefixes(String namespaceURI) {
        return null; // not used
      }
    });
    XPathExpression xpathExpression = xPathProcessor.compile("/t:Message/t:Out/t:Personne/t:CodeCivilite");
    System.out.println();
    Node resultNode = (Node) xpathExpression.evaluate(node, XPathConstants.NODE);
    

    引入一个临时文件,使用默认 DocumentBuilderFactory(不知道命名空间)重新加载,使非限定 XPATH 表达式(没有命名空间)工作。

    希望这很清楚:)

    【讨论】:

      【解决方案2】:

      我想知道解析文件是否会给你一个更短的树。尝试使用 xpath 表达式

      //Message/Out/Personne/CodeCivilite
      

      (前面的双斜线)不带文件 i/o 以查看是否有没有文件 i/o 的额外节点层。

      【讨论】:

        【解决方案3】:

        node = loadXmlFromInputStream(new FileInputStream(xslOutputfile)).getDocumentElement();

        是getDocumentElement()吗?

        你能打印重新加载的节点,看看你是否有你所期望的吗?

        【讨论】:

        • 通过 3 行存储和重新加载 XML 文档,它可以工作,但是当我不这样做时(通过注释这 3 行),它就不再工作了。
        • 只需使用“/”的 XpathExpression 获取节点,然后打印并查看转换后的文档的根是什么。也试试“//”。另一件值得怀疑的事情是某种命名空间阻止了搜索。
        • 我找到了解决方案。这是一个命名空间问题。
        猜你喜欢
        • 2015-02-15
        • 2013-09-17
        • 1970-01-01
        • 1970-01-01
        • 2012-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多