REXML не может выбрать атрибут.Ошибка или неправильный XPath? - PullRequest
1 голос
/ 04 февраля 2011

Я пытаюсь выбрать элемент из документа 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>

Теперь я использую следующий синтаксис для извлечения элемента пути по его атрибуту «тип»:

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".

Ответы [ 4 ]

3 голосов
/ 04 февраля 2011

Похоже, что выбирается более старая версия rexml, которая не поддерживает полную спецификацию XPath.

Попробуйте проверить вывод puts XPath::VERSION, чтобы убедиться, что отображается 3.1.73.

0 голосов
/ 04 февраля 2011

Это наиболее часто задаваемые вопросы: проблема пространства имен по умолчанию.

Решение:

Вместо:

//path[@type]

используйте

//svg:path[@type]
0 голосов
/ 04 февраля 2011

Многие из нас используют 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, будучи дружелюбным к людям, позволит нам разобраться и обойтись без пространств имен несколькими способами, предполагая, что мы знаем, почему пространства имен хороши.

0 голосов
/ 04 февраля 2011

Вам необходимо принять во внимание пространство имен по умолчанию. В XPath 1.0 вам нужно привязать префикс (например, svg) к URI пространства имен http://www.w3.org/2000/svg, а затем использовать путь типа //svg:path[@type]. То, как вы привязываете префикс к URI для оценки XPath, зависит от используемого вами XPath API, боюсь, я не знаю, как это сделать с вашим Ruby API, если вы не найдете метод или свойство в документации API сами, может быть, кто-то другой придет позже, чтобы сказать нам.

...