【问题标题】:xpath for xml document with varying depth具有不同深度的 xml 文档的 xpath
【发布时间】:2016-02-29 07:44:03
【问题描述】:

我有一个 xml 文档,其中有固定的结构,但深度是不同的,例如:-

  1. 有主节点<project>
  2. 它有可能重复多次的子节点<namespace>。在<namespace>之前或之后可能会出现一些新标签。
<project>
 <newtag>
 <namespace>
   <namespace>
     ..........
   </namespace>
 </namespace>
 </newtag>
</project>
  1. 在多个命名空间之后,还有两个我感兴趣的标签&lt;querySubject&gt;&lt;queryItem&gt;

我正在使用特定 XPATH 搜索 queryItem 标记中的文本:-

/project/namespace/namespace/querySubject/queryItem[contains(., 'searchTerm')]/ancestor-or-self::*/name

对于下面给出的特定结构,我的 Xpath 运行良好:-

<project>
<namespace>
        <name locale="en">Test</name>
        <lastChanged>2016-01-12T12:42:46</lastChanged>
            <namespace>
            <name locale="en">Database Layer</name>
                <querySubject status="valid">
                <name locale="en">qskxyz</name>
                    <queryItem>
                    <name locale="en">qixyz</name>
                        <hello>searchTerm</hello>
                    </queryItem>
                </querySubject>
            </namespace>
 </namespace>
 <namespace>
        <name locale="en">Test</name>
        <lastChanged>2016-01-12T12:42:46</lastChanged>
            <namespace>
            <name locale="en">Database Layer</name>
                <querySubject status="valid">
                <name locale="en">qsxyz</name>
                    <queryItem>
                    <name locale="en">myName</name>
                        <hello>...Hi there..</hello>
                    </queryItem>
                </querySubject>
            </namespace>
 </namespace>
 </project>

但如果有上述几点所述的变化,则无法正常工作。任何建议

编辑 1.

我的观察中有一些遗漏

我的实际项目标签是

<project containsDynamicContent="false" xmlns="http://www.developer.cognos.com/schemas/bmt/60/7" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.developer.cognos.com/schemas/bmt/60/7 BMTModelSpecification.xsd">

但是在开发中我采取简单的&lt;project&gt;&lt;/project&gt;

这是有影响的,我的 Xpath 无法正常工作。 我在 Xpath 下尝试过的任何建议,但这也不起作用,我无法更改我的 xml 标签。 我已经尝试过这个 xpath :-

//namespace//querySubject/queryItem[contains(.,'searchTerm')]/ancestor-or-self::*/name 

【问题讨论】:

  • “我正在使用特定 XPATH 搜索 queryItem 标记中的文本” > 但您的 xpath 表达式选择所有 name 祖先节点(或自节点)您选择的queryItem。这是矛盾的。
  • 是的,我正在搜索文本,然后返回所有祖先名称以追踪它

标签: xml xpath


【解决方案1】:

基本上,XPath 表达式是:

/x:project//x:namespace//x:querySubject/x:queryItem[contains(.,'searchTerm')]/ancestor-or-self::*/x:name

那么你需要将命名空间http://www.developer.cognos.com/schemas/bmt/60/7与前缀x相关联。


我将以 Java (1.7) 中的 sn-p 为例。这将使用 XPath 表达式注册一个 NamespaceContext,该表达式解析前缀的命名空间(在本例中为 x)。 sn-p 是一个简单的示例,它甚至不检查传递给NamespaceContext.getNamespaceURI 的前缀。典型实现使用映射将 URI 映射到前缀。

其他开发环境应该有类似的功能。


import java.io.StringReader;
import java.util.Iterator;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.*;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class XPathInXmlns {
    private static final String xml=
"<project containsDynamicContent=\"false\" xmlns=\"http://www.developer.cognos.com/schemas/bmt/60/7\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.developer.cognos.com/schemas/bmt/60/7 BMTModelSpecification.xsd\">"+
"   <namespace>"+
"           <name locale=\"en\">Test</name>"+
"           <lastChanged>2016-01-12T12:42:46</lastChanged>"+
"               <namespace>"+
"               <name locale=\"en\">Database Layer</name>"+
"                   <querySubject status=\"valid\">"+
"                   <name locale=\"en\">qskxyz</name>"+
"                       <queryItem>"+
"                       <name locale=\"en\">qixyz</name>"+
"                           <hello>searchTerm</hello>"+
"                       </queryItem>"+
"                   </querySubject>"+
"               </namespace>"+
"    </namespace>"+
"    <namespace>"+
"           <name locale=\"en\">Test</name>"+
"           <lastChanged>2016-01-12T12:42:46</lastChanged>"+
"               <namespace>"+
"               <name locale=\"en\">Database Layer</name>"+
"                   <querySubject status=\"valid\">"+
"                   <name locale=\"en\">qsxyz</name>"+
"                       <queryItem>"+
"                       <name locale=\"en\">myName</name>"+
"                           <hello>...Hi there..</hello>"+
"                       </queryItem>"+
"                   </querySubject>"+
"               </namespace>"+
"    </namespace>"+
" </project>";

    private static final String xpathExpr=
"/x:project//x:namespace//x:querySubject/x:queryItem[contains(.,'searchTerm')]/ancestor-or-self::*/x:name/text()";

    public static void main(String[] args) {
        try {
            XPath xpath = XPathFactory.newInstance().newXPath();
            xpath.setNamespaceContext(new NamespaceContext() {
                @Override
                public Iterator getPrefixes(String namespaceURI) {
                    return null;
                }
                @Override
                public String getPrefix(String namespaceURI) {
                    return null;
                }
                @Override
                public String getNamespaceURI(String prefix) {
                    return "http://www.developer.cognos.com/schemas/bmt/60/7";
                }
            });
            XPathExpression expr = xpath.compile(xpathExpr);
            NodeList nodeList = (NodeList) expr.evaluate(new InputSource(new StringReader(xml)),XPathConstants.NODESET);
            for( int i = 0; i != nodeList.getLength(); ++i )
                System.out.println(nodeList.item(i).getNodeValue());
        } catch (XPathExpressionException e) {
            e.printStackTrace();
        }
    }
}

输出:

Test
Database Layer
qskxyz
qixyz

【讨论】:

  • 我想我在xml中遗漏了一些东西,因为它不起作用..找到后会更新
  • @user2816085 我用你的 xml 进行了测试,在命名空间元素之前和之后添加了随机元素,插入了多个额外的命名空间......对我有用。
  • 所以这个问题与stackoverflow.com/questions/10981312/…重复
  • @user2816085 更新了 Java 中的示例。
猜你喜欢
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多