【问题标题】:XPath returns null when I remove the prefix删除前缀时 XPath 返回 null
【发布时间】:2011-04-10 16:04:34
【问题描述】:

我在 Eclipse 下的 Java 中使用 XPath。我正在编写一个肥皂网络服务,XML 使用前缀和命名空间,我想删除前缀并只保留命名空间,因为我更喜欢看起来更易读的 XML 文档。

当我从 XML 定义文件中删除前缀并尝试使用 XPath 查询 XML 时,我开始为 XML 中的每个节点获取 null!

我的问题是,如果我想使用 XPath,我必须使用前缀吗?仅仅是命名空间就够了吗?

<myrequest
    xmlns="http://www.mywebsite.com/xml/webservice"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.mywebsite.com/xml/webservice Request.xsd">

   <state>     
       <value>demox</value>

这就是我的 XML 的开始方式,当我使用像 XPath.selectSingleNode() 这样的 XPath 查询它时,我总是从 XPath 中收到其中每个节点的 null。

String myExpression = "myrequest/state/value";  
Document doc = new Document(requestXML);    
Element e = doc.getRootElement();
request.setMybase(getBase((org.jdom.Element) 
            XPath.selectSingleNode(doc,myExpression)));

【问题讨论】:

  • 好问题,+1。请参阅我的答案以获得完整的解释和解决方案。

标签: java xml xpath xsi


【解决方案1】:

这是关于几个 XPath 相关标签的最常见问题解答

只要 XML 文档中有默认命名空间(如您的情况),XPath 表达式中的任何元素名称都必须以绑定到该默认命名空间的前缀作为前缀。绑定是在 XPath 的宿主语言中执行的,通常是使用特定的方法/函数“注册默认命名空间”。

必须这样做的原因

只要 XPath 表达式中有一个不带前缀的名称,XPath 就会将此名称视为属于“无命名空间”。

这是来自XPath 1.0 W3C Specification的规范文本:

"节点测试中的 QName 使用表达式上下文中的命名空间声明扩展为扩展名称。这与对开始和结束标记中的元素类型名称进行扩展的方式相同,除了不使用xmlns声明的默认命名空间:如果QName没有前缀,则命名空间URI为空(这与扩展属性名称的方式相同)。如果QName是错误的有一个前缀,在表达式上下文中没有命名空间声明".

因此,在具有默认命名空间的文档上评估 /a/b/c 意味着:选择所有位于“无命名空间”中且名为 c 的元素,其父元素是名为 b 且位于“无命名空间”中的元素",其父元素是 xml 文档的顶部元素,名为 a,位于“无命名空间”中。

由于文档中的所有元素都在其默认命名空间中,而不是在“无命名空间”中,因此此 XPath 表达式不选择任何内容

解决方案

  1. 在 XPath 引擎的 API 中,注册默认命名空间并绑定一个前缀(比如“x”)。

  2. 现在您可以而且必须使用这个 XPath 表达式:/x:myrequest/x:state/x:value 而不是 /myrequest/state/value

【讨论】:

    【解决方案2】:

    使用 XPath 1.0 选择命名空间中的元素,您需要在 XPath 表达式中使用前缀来限定元素名称。因此,即使将 XML 清理为在 XPath 表达式中不使用前缀而是使用默认名称空间声明,您也需要使用绑定到您拥有的默认名称空间 (http://www.mywebsite.com/xml/webservice) 的前缀。如何将前缀绑定到命名空间 URI 取决于您使用的 XPath API,我对 JDOM 不熟悉,请自行查看其 API 以了解如何将前缀绑定到命名空间 URI。

    [编辑]方法是http://www.jdom.org/docs/apidocs/org/jdom/xpath/XPath.html#addNamespace%28java.lang.String,%20java.lang.String%29。所以选择您喜欢的任何前缀(例如“pf”)并执行addNamespace("pf", "http://www.mywebsite.com/xml/webservice"),然后在您的 XPath 中使用该前缀(例如“pf:myrequest/pf:state/pf:value”)。

    【讨论】:

      【解决方案3】:

      我的问题是我必须使用 如果我想使用 Xpath 前缀?不是 只是命名空间就够了吗?

      如果您想使用 XPath,则不必使用命名空间前缀。只需命名空间就足够了,但如果您注册并使用命名空间前缀,它会使您的 XPath 更加简洁、易于阅读和维护。

      可以使用 XPath 与指定 local-name()namespace-uri() 条件的谓词过滤器的元素(即 *)进行通用匹配,如下所示:

      /*[local-name()='myrequest' 
         and namespace-uri()='http://www.mywebsite.com/xml/webservice'] 
          /*[local-name()='state' 
             and namespace-uri()='http://www.mywebsite.com/xml/webservice']
            /*[local-name()='value' 
               and namespace-uri()='http://www.mywebsite.com/xml/webservice']
      

      但是,注册命名空间并在 XPath 中使用命名空间前缀要容易得多。(例如 /ws:myrequest/ws:state/ws:value

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-08
        • 1970-01-01
        • 2019-04-07
        相关资源
        最近更新 更多