【问题标题】:REXML fails to select from attribute. Bug or incorrect XPath?REXML 无法从属性中进行选择。错误或不正确的 XPath?
【发布时间】:2011-02-04 12:47:48
【问题描述】:

我尝试通过特殊属性从 SVG 文档中选择一个元素。 我设置了一个简单的例子。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
  <g id='1'>
    <path id='2' type='A'/>
    <rect id='3' type='B'/>
  </g>
</svg>

现在我使用以下语法通过属性“type”检索路径元素:

require 'rexml/document'
include REXML
xmlfile = File.new "xml_as_specified_above.svg"
xmldoc = Document.new(xmlfile)
XPath.match( xmldoc.root, "//path[@type]" )

直接来自http://www.w3schools.com/xpath/xpath_syntax.asp 的语法。 我希望这个表达式选择路径元素,但如下所示:

>> XPath.match( xmldoc.root, "//path[@type]" )
=> []

那么,在 XPath 中通过属性来寻址路径元素的正确语法是什么? 或者 REXML 中是否存在错误(使用 3.1.7.3)? 还可以检索“rect”元素。

【问题讨论】:

  • 我刚刚尝试了您上面的代码,它在这里工作正常。如果您使用更简单的“//path”XPath 而不需要type 属性,它是否有效?
  • 您确定正在使用 3.1.7.3 并且在您的 Ruby 路径中没有潜伏旧版本吗?尝试检查puts XPath::VERSION的输出
  • XPath::VERSION 是 1.8.7。 //path XPath 按预期工作并提供路径元素。
  • 啊哈!那时正在使用旧版本的 rexml。早期版本没有VERSION 常量,因此您看到的1.8.7 实际上是Ruby 版本的顶级VERSION 常量,而不是rexml 版本。旧版本不支持完整的 XPath 规范,因此 @type 不起作用。
  • 所以如果你能把它放在一个答案中,我会接受它 - 谢谢!

标签: ruby xpath rexml


【解决方案1】:

似乎正在选择不支持完整 XPath 规范的旧版本的 rexml。

尝试检查puts XPath::VERSION 的输出以确保显示3.1.73。

【讨论】:

  • 这个答案是错误的,因为//path[@type] 绝不应该选择提供的输入样本中的任何元素。如果这是可能的,那么你就不能再使用这个 XPath 引擎了,因为这不是标准的抱怨。
【解决方案2】:

您需要考虑默认命名空间。使用 XPath 1.0,您需要将前缀(例如 svg)绑定到命名空间 URI http://www.w3.org/2000/svg,然后使用类似 //svg:path[@type] 的路径。如何将前缀绑定到 URI 以进行 XPath 评估取决于您使用的 XPath API,如果您在 API 文档中找不到方法或属性,恐怕我不知道您的 Ruby API 是如何完成的你自己然后也许其他人稍后会告诉我们。

【讨论】:

  • 但是文档的默认命名空间不是已经绑定到w3.org/2000/svg了吗?此外,可以使用 //path 作为 XPath 元素访问该元素。所以在我看来//path[@type] 应该也可以。
  • 在 XPath 1.0 中,路径 foo 在没有命名空间的情况下选择本地名称为 foo 的元素。 SVG 元素位于某个命名空间中,因此对于 XPath 1.0,您需要将前缀绑定到 SVG 命名空间 URI 并使用该前缀。这就是 XPath 1.0 的定义和操作方式。正如我所说,我不知道你的实现以及它是否符合标准。
  • +1 正确答案。 这是大型 XPath 常见问题解答//path 将选择空或 null 命名空间 URI 下的任何 path 元素。
【解决方案3】:

如今,我们中的许多人都使用Nokogiri,而不是 ReXML 或 Hpricot,这是另一个早期的 Ruby XML 解析器。

Nokogiri 支持 XPath 和 CSS 访问器,因此您可以使用熟悉的 HTML 类型路径来获取节点:

require 'nokogiri'

svg = %q{<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
  <g id='1'>
    <path id='2' type='A'/>
    <rect id='3' type='B'/>
  </g>
</svg>
}

doc = Nokogiri::XML(svg)
puts doc.search('//svg:path[@type]')
puts doc.search('svg|path[@type]')
puts doc.search('path[@type]')

puts doc.search('//svg:rect')
puts doc.search('//svg:rect[@type]')
puts doc.search('//svg:rect[@rect="B"]')
puts doc.search('svg|rect')
puts doc.search('rect')

# >> <path id="2" type="A"/>
# >> <path id="2" type="A"/>
# >> <path id="2" type="A"/>

# >> <rect id="3" type="B"/>
# >> <rect id="3" type="B"/>
# >> <rect id="3" type="B"/>
# >> <rect id="3" type="B"/>

第一个路径是带有命名空间的 XPath。第二个是带有命名空间的 CSS。第三个是没有命名空间的 CSS。对人类友好的 Nokogiri 将使我们能够deal and dispense with the namespaces 几种方式,假设我们知道为什么命名空间是好的。

【讨论】:

    【解决方案4】:

    这是最常见的问题:默认命名空间问题。

    解决方案:

    代替:

    //path[@type]
    

    使用

    //svg:path[@type]
    

    【讨论】:

      猜你喜欢
      • 2018-03-31
      • 2023-03-05
      • 1970-01-01
      • 2018-08-08
      • 1970-01-01
      • 1970-01-01
      • 2012-03-25
      • 1970-01-01
      相关资源
      最近更新 更多