Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何通过XPATH更新Java中需要不同值的多个节点?_Java_Xml_Xpath - Fatal编程技术网

如何通过XPATH更新Java中需要不同值的多个节点?

如何通过XPATH更新Java中需要不同值的多个节点?,java,xml,xpath,Java,Xml,Xpath,当需要处理具有不同名称的字段时,如何通过一条XPATH语句更新多个节点?给定如下模式: <?xml version="1.0" encoding="UTF-8"?> <PersonList> <Person> <Name>Adam West </Name> <Age> 72 </Age> </Person> </Pers

当需要处理具有不同名称的字段时,如何通过一条XPATH语句更新多个节点?

给定如下模式:

<?xml version="1.0" encoding="UTF-8"?>  
<PersonList>  
    <Person>  
          <Name>Adam West </Name>  
          <Age> 72 </Age>
    </Person>  
</PersonList>  

我不确定你在发布这个问题时的目标是什么,但是我看到你自己的答案有几个问题

XPath是一种将谓词应用于DOM树的工具。使用XPath选择一组比您需要的更大的节点,然后将您自己的谓词应用于它返回的节点列表是没有意义的。 XPath表达式包含多个正交项。评估效率较低,并且在添加其他术语时很快变得难以管理。 您正在使用的表达式——检索文本节点,然后导航到父元素——没有多大意义。我假设您只希望选择已经有文本的节点,但是如果您正在进行全局搜索和替换,我不确定这是一个合理的假设。如果我要继承您的代码,我当然希望看到演示这两种行为的测试,以此表明您有意这样做。 众所周知,长串的if/else语句很难理解。它们也很难测试,因为您必须创建一个测试套件来执行代码中所有可能的路径。 if语句的主体是重复的代码,违反了DRY原则。如果需要从选定节点向上导航,则可能会出现错误,或者如果更改指定表达式的方式,则必须在多个位置复制和粘贴代码。 在我看来,提取一个方法来选择节点并一次对单个表达式执行更改要好得多。从您的代码开始,让我的IDE修复一些语法错误,我最终得到了这个结果,但是,我还没有编写测试用例:

public static void main(String[] args) throws Exception  
{  
     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
     DocumentBuilder builder = factory.newDocumentBuilder();  
     Document doc = builder.parse(new File("path/to/file.xml"));  

     changeNodeText(doc, "/PersonList/Person/Age", "42");
     changeNodeText(doc, "/PersonList/Person/Name", "Batman");
}  


public static void changeNodeText(Node context, String xpath, String value)
throws XPathExpressionException
{
    XPathFactory xFactory = XPathFactory.newInstance();
    XPath xPath = xFactory.newXPath();
    XPathExpression expression = xPath.compile(xpath);
    NodeList nodes = (NodeList)expression.evaluate(context, XPathConstants.NODESET);
    for (int i = 0; i < nodes.getLength(); i++)
    {
        Node node = nodes.item(i);
        node.setTextContent(value);
    }
}
除了我在上面所做的XPath特定注释之外,还有一些关键特性:

函数名表明您正在更改节点的文本。 您可以很容易地看到正在更新的路径;您不必遍历代码来了解它在做什么。 您可以使用两个测试用例来测试它,一个是肯定的,另一个是否定的,并推断它在任何地方都可以工作。 它使用setTextContent方法,IMO比setNodeValue有更好的规范,除非传递文本节点,否则setNodeValue将失败。 如果必须添加名称空间映射,可以在一个位置进行。如果您决定只更改已经有文本节点的元素,则同上。
我认为需要一个输入数据和期望输出的示例。不过,您可能也需要重新表述这个问题,因为XPath本身无法更新任何内容。@LarsH事后看来是的。显式检索不同节点集的代码会更少。更容易理解,;“没有什么事情比一个巨大的if-else连锁店更糟糕了。”帕西法尔,如果你有推荐信,请给出答案。这就是为什么我如此喜欢这个网站。一个新的更好的答案被张贴,我可以接受它超过我的答案。然而,我会包括一些最完整的东西。1包括包导入,有多个文档和节点。2如我在回答中所做的那样,添加一个示例XML将有助于使其尽可能完整。
public static void main(String[] args) throws Exception  
{  
     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
     DocumentBuilder builder = factory.newDocumentBuilder();  
     Document doc = builder.parse(new File("path/to/file.xml"));  

     changeNodeText(doc, "/PersonList/Person/Age", "42");
     changeNodeText(doc, "/PersonList/Person/Name", "Batman");
}  


public static void changeNodeText(Node context, String xpath, String value)
throws XPathExpressionException
{
    XPathFactory xFactory = XPathFactory.newInstance();
    XPath xPath = xFactory.newXPath();
    XPathExpression expression = xPath.compile(xpath);
    NodeList nodes = (NodeList)expression.evaluate(context, XPathConstants.NODESET);
    for (int i = 0; i < nodes.getLength(); i++)
    {
        Node node = nodes.item(i);
        node.setTextContent(value);
    }
}