不同位置的节点的通用xpath

时间:2015-01-28 14:41:04

标签: java xml xpath

我有很多来自不同版本的架构的xml文件。这些xmls中的某些部分/标签是相同的 我想要做的是找到一个特定标签并开始处理该标签。问题是这个标签可能出现在xml的不同位置 所以我正在寻找一个xpath来定位这个节点而不管它的位置。我使用Java编写处理代码。
以下是xmls的各种falv
样本1

<nodeIWant>
       <book>
          <title>Harry Potter and the Philosophers Stone</title>
          ...
       </book>
</nodeIWant>

样本2

<a>
   <nodeIWant>
      <book>
         <title>Harry Potter and the Philosophers Stone</title>
         ...
      </book>
   </nodeIWant>
</a>

样本3

<b>
   <nodeIWant>
      <book>
         <title>Harry Potter and the Philosophers Stone</title>
         ...
      </book>
   </nodeIWant>
</b>

在上面的xmls中,我想使用相同的xpath来定位节点' nodeIWant '。

我使用的Java代码如下

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document modelDoc = docBuilder.parse(args[0]);

XPath xPath = XPathFactory.newInstance().newXPath();
System.out.println(xPath.evaluate("//nodeIWant", modelDoc.getDocumentElement(), XPathConstants.NODE));

这会打印出一个空值。

最终修改
MathiasMüller的答案适用于这些xml文件。我实际上是在尝试查询Rational Software Architect中的.emx文件。我试图尝试使用这些例子。 (请不要开始谈论BIRT和使用eclipse uml API等...我已经尝试过这些并且他们没有给我我想要的东西。) 文件的结构如下

    <?xml version="1.0" encoding="UTF-8"?>
<!--xtools2_universal_type_manager-->
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.uml.msl.model" version="7.0.0"><feature description="" name="com.ibm.xtools.ruml.feature" url="" version="7.0.0"/></signature>?>
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.mmi.ui.signatures.diagram" version="7.0.0"><feature description="" name="Rational Modeling Platform (com.ibm.xtools.rmp)" url="" version="7.0.0"/></signature>?>
<xmi:XMI version="2.0" xmlns:Default="http:///schemas/Default/_fNm3AAqoEd6-N_NOT9vsCA/2" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/3.0.0/UML" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http:///schemas/Default/_fNm3AAqoEd6-N_NOT9vsCA/2 pathmap://UML2_MSL_PROFILES/Default.epx#_fNwoAAqoEd6-N_NOT9vsCA?Default/Default?">
  <uml:Model name="A" xmi:id="_4lzSsMywEeGAuoBpYhfj6Q">
  <!-- Lot of other stuff -->
  </uml:Model>
<xmi:XMI>


另一个文件是

    <?xml version="1.0" encoding="UTF-8"?>
<!--xtools2_universal_type_manager-->
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.uml.msl.model" version="7.0.0"><feature description="" name="com.ibm.xtools.ruml.feature" url="" version="7.0.0"/></signature>?>
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.mmi.ui.signatures.diagram" version="7.0.0"><feature description="" name="Rational Modeling Platform (com.ibm.xtools.rmp)" url="" version="7.0.0"/></signature>?>
<uml:Model xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/3.0.0/UML" xmi:id="_4lzSsMywEeGAuoBpYhfj6Q" name="A">
<!-- Lot of other stuff -->
</uml:Model>


'// Model'的xpath不应该适用于这两个样本吗?

3 个答案:

答案 0 :(得分:2)

您可以使用xPath'轴'//。这将在文件中搜索您的节点,而不关心父节点。所以在你的例子中你可以使用:

//nodeIWant

答案 1 :(得分:1)

对DocumentBuilder不是很熟悉,但是你可能需要在对文档进行评估之前编译XPath表达式吗?似乎不是评估的XPath表达式,XML文档是。

String expression = "//nodeIWant";
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(modelDoc, XPathConstants.NODESET);

或者,如果只有其中一个元素,并且您想要打印其字符串值:

String expression = "//nodeIWant";
System.out.println(xPath.compile(expression).evaluate(modelDoc));

编辑:您编辑了问题并显示了正在评估路径表达式的实际 XML。这些新文档具有名称空间,您需要在XPath表达式中考虑这些名称。

//nodeIWant永远不会找到一个节点,如果它实际上在命名空间中。要在新文档中找到Model节点,您必须使用

//*[local-name() = 'Model']

答案 2 :(得分:0)

由于您提供的示例在String元素中不仅包含<nodeIWant>,因此您可以从使用面向对象的方法与xpath结合中获益。使用data projection(披露:我与该项目有关联),可以这样做:

public class DataProjection {

public interface Book {

    @XBRead("./title")
    String getTitle();

    //... more getter or setter methods
}

public static void main(String[] args) {
    // Print all books in all <nodeIWant> elements of 
    for (String file : new String[] { "a.xml", "b.xml", "c.xml" }) {
        List<Book> books = new XBProjector().io().file(file).evalXPath("//nodeIWant/book").asListOf(Book.class);
        for (Book book : books) {
            System.out.println(book.getTitle());
        }
    }
  }
}

您可以为XML数据定义一个或多个视图(称为投影接口),并使用XPath将数据连接到实现这些接口的Java对象。这有助于构建代码并使其可重用于类似的XML文件。