使用XPath输出具有未知节点深度的XML内容

时间:2014-04-10 10:14:32

标签: java xml xpath recursion

我想从XML字符串中提取信息路径:

"/root/A/info1"
"/root/A/B/info2"
"/root/A/B/info3"
"/root/A/info4"

这是输入:

<root>
  <A>
    <info1>value1</info1>
    <B>
      <info2>value2.1</info2>
      <info3>value3.1</info3>
    </B>
    <B>
      <info2>value2.2</info2>
      <!-- note: element "info3" is missing here! -->
    </B>
    <B>
      <info2>value2.3</info2>
      <info3>value3.3</info3>
    </B>
    <info4>value4</info4>
  </A>
 </root>

我想实现这个目标:

value1|value2.1|value3.1|value4
value1|value2.2|NULL|value4
value1|value2.3|value3.3|value4

我的路径各不相同,我从不知道XML文件的深度。由于"/root/A/B/info2""/root/A/B/info3"存在三次,我显然需要输出三行。 我认为这里需要递归。


我的代码:

主要功能:

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(new ByteArrayInputStream(xml.getBytes()));   

String[] paths = new String[] {"/root/A/info1", "/root/A/B/info2", "/root/A/B/info3", "/root/A/info4"};

XPath xPath = XPathFactory.newInstance().newXPath();
String[] output = new String[paths.length];

for(int i=0; i<paths.length; i++) {
  recursion(paths, doc, xPath, paths[i], i, output);
}

递归函数:

private static void recursion(String[] paths, Object parent, XPath xPath, String path, int position, String[] output) throws Exception {
  if(path.contains("/")) { // check if it's the last element, which contains the needed value
    List<String> pathNodes = new ArrayList(Arrays.asList(StringUtils.split(path, "/")));

    String currentPathNode = pathNodes.get(0);

    NodeList nodeList = (NodeList) xPath.compile(currentPathNode).evaluate(parent, XPathConstants.NODESET);

    pathNodes.remove(0);

    String newPath = StringUtils.join(pathNodes, "/");

    for(int i=0; i<nodeList.getLength(); i++) {
      Node node = nodeList.item(i);

      recursion(paths, node, xPath, newPath, position, output.clone()); // clone?
    }
  }
  else {
    output[position] = xPath.compile(path).evaluate(parent);

    if((position + 1) == paths.length) { // check if it's the last path, so output the values
      System.out.println(StringUtils.join(output, "|"));
    }
  }
}

如果我克隆output,我会得到这个:

|||value4

如果我不克隆output我得到了(覆盖以前的值):

value1|value2.3|value3.3|value4

请给我一个提示。

更新:再次查看XML输入。没有价值的文本元素可能会丢失。

1 个答案:

答案 0 :(得分:0)

我终于解决了它。

我为我的应用程序添加了一个上下文路径。它指定哪个元素是最深的。

在我的示例中,它将是"/root/A/B"

我将所有路径更新为相对于该上下文路径:

"../info1"
"info2"
"info3"
"../info4"

然后我从上下文路径(这里是3)计算节点。这也是将要创建的行数。我创建一个循环来迭代它们并使用XPath查询我更新的路径。