不同位置节点的通用 xpath
Generic xpath for a node at different locations
我有很多来自不同版本架构的 xml 文件。这些xml中有某些sections/tags是相同的。
我想要做的是找到一个特定的标签并开始处理该标签。问题是这个标签可能出现在 xml.
中的不同位置
所以我正在寻找一个 xpath 来定位这个节点,而不管它的位置。我正在使用 Java 来编写我的处理代码。
以下是 xmls
的各种恩惠
样本 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));
这将打印出一个空值。
最终编辑
Mathias Mü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 不应该也适用于这两个示例吗?
您可以使用 xPath 'axis' //
。这会在文件中搜索您的节点并且不关心父节点。所以在你的例子中你可以使用:
//nodeIWant
不太熟悉 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']
由于您提供的示例在 <nodeIWant>
元素中包含的不仅仅是 String
,您可能可以从结合使用面向对象的方法和 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 文件。
我有很多来自不同版本架构的 xml 文件。这些xml中有某些sections/tags是相同的。
我想要做的是找到一个特定的标签并开始处理该标签。问题是这个标签可能出现在 xml.
中的不同位置
所以我正在寻找一个 xpath 来定位这个节点,而不管它的位置。我正在使用 Java 来编写我的处理代码。
以下是 xmls
的各种恩惠
样本 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));
这将打印出一个空值。
最终编辑
Mathias Mü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 不应该也适用于这两个示例吗?
您可以使用 xPath 'axis' //
。这会在文件中搜索您的节点并且不关心父节点。所以在你的例子中你可以使用:
//nodeIWant
不太熟悉 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']
由于您提供的示例在 <nodeIWant>
元素中包含的不仅仅是 String
,您可能可以从结合使用面向对象的方法和 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 文件。