使用Saxon修改XPath 2.0结果树

使用Saxon修改XPath 2.0结果树,saxon,xpath-2.0,Saxon,Xpath 2.0,我想 向“子树”添加/删除/更新元素/属性/值 能够将更新后的“targetDoc”保存回“target”文件位置 确定哪个树模型最适合这个xpath+树修改过程 我想我应该能够以某种方式获得一个MutableNodeInfo对象,但我不知道如何做到这一点。我尝试使用processor.setConfigurationProperty(FeatureKeys.TREE\u MODEL,Builder.LINKED\u TREE);但这仍然为我提供了TinyElementImpl的一个底层节点。我

我想

  • 向“子树”添加/删除/更新元素/属性/值
  • 能够将更新后的“targetDoc”保存回“target”文件位置
  • 确定哪个树模型最适合这个xpath+树修改过程
  • 我想我应该能够以某种方式获得一个MutableNodeInfo对象,但我不知道如何做到这一点。我尝试使用processor.setConfigurationProperty(FeatureKeys.TREE\u MODEL,Builder.LINKED\u TREE);但这仍然为我提供了TinyElementImpl的一个底层节点。我需要XPath2.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();
        }
    
    }
    
    publicstaticvoidmain(字符串[]args){
    //XML文件名称空间URI
    Hashtable namespaceURIs=新的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");
    //源/目标xml文档
    String target=“file.xml的路径”;
    //xpath字符串
    字符串xpath=“/ODM/Study/MetaDataVersion/ItemGroupDef[@OID/String()='IG.TA']”;
    处理器=新处理器(真);
    //我想这会告诉处理器使用其他东西,而不是
    //锡树
    processor.setConfigurationProperty(FeatureKeys.TREE_模型,
    链接树);
    DocumentBuilder=processor.newDocumentBuilder();
    XPathCompiler XPathCompiler=processor.newXPathCompiler();
    for(条目:namespaceURIs.entrySet()){
    declareNamespace(entry.getKey(),entry.getValue());
    }
    试一试{
    XdmNode targetDoc=builder.build(path.get(target.toFile());
    XPathSelector=xpathCompiler.compile(xpath.load();
    选择器.setContextItem(targetDoc);
    XdmNode子树=(XdmNode)选择器.evaluateSingle();
    //以下打印:类
    //net.sf.saxon.tree.tiny.TinyElementImpl
    System.out.println(subTree.getUnderlyingNode().getClass());
    /*
    *在这里,我想修改子树并保存修改后的文档
    */
    }捕获(萨克森例外){
    e、 printStackTrace();
    }
    }
    
    我认为您可以向Saxon提供一个DOM节点并对其运行XPath,但在这种情况下,您不需要为Saxon的原生树使用文档生成器,您可以使用
    javax.xml.parsers.DocumentBuilder
    构建一个DOM,一旦有了W3CDOM节点,就可以使用Saxon
    DocumentBuilder的
    wrap
    方法将其提供给Saxon。以下是从中的文件S9APIExamples.java中获取的示例代码:


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

    Saxon中的可变节点信息接口是专为满足XQuery更新的需要而设计的,我建议不要尝试直接从Java使用它;当处理XQuery Update发出的方法调用以外的方法调用时,该实现可能不太健壮


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

    谢谢。这很好用。甚至在使用默认JavaDOM时,XPath2.0的某些元素也可以使用这种方法。在试图提出解决方案时,我不知何故忽略了DocumentBuilder.wrap()的使用。另外,感谢@Michael Kay澄清了MutableNodeInfo和建议树模型的使用。
            // 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());
            }