【问题标题】:Modifying XPath 2.0 result trees using Saxon使用 Saxon 修改 XPath 2.0 结果树
【发布时间】:2015-03-04 05:18:58
【问题描述】:

我愿意

  1. 向“子树”添加/删除/更新元素/属性/值
  2. 能够将更新后的“targetDoc”保存回“target”文件位置。
  3. 确定最适合此 xpath + 树修改过程的树模型。

我认为我应该能够以某种方式获得一个 MutableNodeInfo 对象,但我不知道该怎么做。我尝试使用 processor.setConfigurationProperty(FeatureKeys.TREE_MODEL, Builder.LINKED_TREE);但这仍然给了我 TinyElementImpl 的底层节点。我需要 xpath 2.0 以避免必须输入默认命名空间,这就是我使用 saxon s9api 而不是 Java 的默认 DOM 模型的原因。如果可能的话,我还想避免使用 xslt/xquery,因为这些树修改是动态完成的,这使得 xslt/xquery 在我的情况下更加复杂。

public static void main(String[] args) {

    // XML File namesspace URIs
    Hashtable<String, String> namespaceURIs = new Hashtable<>();
    namespaceURIs.put("def", "http://www.cdisc.org/ns/def/v2.0");
    namespaceURIs.put("xmlns", "http://www.cdisc.org/ns/odm/v1.3");
    namespaceURIs.put("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    namespaceURIs.put("xlink", "http://www.w3.org/1999/xlink");
    namespaceURIs.put("", "http://www.cdisc.org/ns/odm/v1.3");
    // The source/target xml document
    String target = "Path to file.xml";
    // An xpath string
    String xpath = "/ODM/Study/MetaDataVersion/ItemGroupDef[@OID/string()='IG.TA']";

    Processor processor = new Processor(true);
    // I thought this tells the processor to use something other than
    // TinyTree
    processor.setConfigurationProperty(FeatureKeys.TREE_MODEL,
            Builder.LINKED_TREE);
    DocumentBuilder builder = processor.newDocumentBuilder();
    XPathCompiler xpathCompiler = processor.newXPathCompiler();
    for (Entry<String, String> entry : namespaceURIs.entrySet()) {
        xpathCompiler.declareNamespace(entry.getKey(), entry.getValue());
    }
    try {
        XdmNode targetDoc = builder.build(Paths.get(target).toFile());
        XPathSelector selector = xpathCompiler.compile(xpath).load();
        selector.setContextItem(targetDoc);
        XdmNode subTree = (XdmNode) selector.evaluateSingle();
        // The following prints: class
        // net.sf.saxon.tree.tiny.TinyElementImpl
        System.out.println(subTree.getUnderlyingNode().getClass());

        /*
         * Here, is where I would like to modify subtree and save modified doc
         */

    } catch (SaxonApiException e) {
        e.printStackTrace();
    }

}

【问题讨论】:

    标签: saxon xpath-2.0


    【解决方案1】:

    我认为您可以向 Saxon 提供一个 DOM 节点并对其运行 XPath,但如果您不使用 Saxon 的本地树的文档构建器,您可以使用 javax.xml.parsers.DocumentBuilder 构建一个 DOM,并且一旦您拥有 W3C DOM 节点,您可以使用 Saxon DocumentBuilder 的 wrap 方法将其提供给 Saxon。以下是取自Saxon 9.6 resources file 中的文件 S9APIExamples.java 的示例代码:

            // Build the DOM document
            File file = new File("data/books.xml");
            DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
            dfactory.setNamespaceAware(true);
            javax.xml.parsers.DocumentBuilder docBuilder;
            try {
                docBuilder = dfactory.newDocumentBuilder();
            } catch (ParserConfigurationException e) {
                throw new SaxonApiException(e);
            }
            Document doc;
            try {
                doc = docBuilder.parse(new InputSource(file.toURI().toString()));
            } catch (SAXException e) {
                throw new SaxonApiException(e);
            } catch (IOException e) {
                throw new SaxonApiException(e);
            }
            // Compile the XPath Expression
            Processor proc = new Processor(false);
            DocumentBuilder db = proc.newDocumentBuilder();
            XdmNode xdmDoc = db.wrap(doc);
            XPathCompiler xpath = proc.newXPathCompiler();
            XPathExecutable xx = xpath.compile("//ITEM/TITLE");
            // Run the XPath Expression
            XPathSelector selector = xx.load();
            selector.setContextItem(xdmDoc);
            for (XdmItem item : selector) {
                XdmNode node = (XdmNode) item;
                org.w3c.dom.Node element = (org.w3c.dom.Node) node.getExternalNode();
                System.out.println(element.getTextContent());
            }
    

    还有一些示例展示了如何将 Saxon 与 JDOM 和其他可变树实现一起使用,但我认为您需要 Saxon PE 或 EE 才能直接支持这些。

    【讨论】:

    • 谢谢。这完美地工作。这甚至适用于 xpath 2.0 的某些元素,即使在使用默认 Java dom 时也是如此。在尝试提出解决方案时,我不知何故忽略了 DocumentBuilder.wrap() 的使用。另外,感谢@Michael-Kay 澄清 MutableNodeInfo 的使用和建议的树模型。
    【解决方案2】:

    Saxon 中的 MutableNodeInfo 接口是专门为满足 XQuery 更新的需要而设计的,我建议不要尝试直接从 Java 中使用它;在处理除 XQuery Update 之外的方法调用时,实现不太可能是健壮的。

    事实上,Saxon NodeInfo 接口通常被设计为 XPath 的目标,而不是用户编写的 Java 代码。因此,我建议使用第三方树模型;我最喜欢的是 JDOM2 和 XOM。这两者都允许您混合使用直接 Java 导航和使用 Saxon 使用 XPath 2.0 导航进行更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-29
      相关资源
      最近更新 更多