关于ruby:为什么无法从根元素中带有名称空间的XPath获得结果?

Why can't I get a result from an XPath with namespace in the root element?

本问题已经有最佳答案,请猛点这里访问。

这可能是XML命名空间的新手问题,但我不知道如何通过特定的根元素使XPath与以下截短的XML一起使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<CreateOrUpdateEventsRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dhamma.org" version="3-0-0">
   <LanguageKey>
    <IsoCode>en</IsoCode>
  </LanguageKey>
  <Publish>
    <Value>true</Value>
  </Publish>
  <Events>
    <Event>
      <EventKey>
        <LocationKey>
          <SubDomain>rasmi</SubDomain>
        </LocationKey>
        <EventId>10DayPDFStdTag</EventId>
      </EventKey>
    </Event>
  </Events>
   </LanguageKey>
</CreateOrUpdateEventsRequest>

使用Ruby和Nokogiri(带有刚刚更新的libxml2),仅当我删除根元素中的所有额外信息时,它才能与XPath一起正常工作,使其成为:

1
<CreateOrUpdateEventsRequest>

否则没有任何效果:

1
2
3
4
$> @doc.xpath("//CreateOrUpdateEventsRequest") #=> [] with original header, an array of nodes with modified header
$> @doc.xpath("//LanguageKey") #=> [] with the original header, an array of nodes with modified header

$> @doc.xpath("//xmlns:LanguageKey") #=> undefined namespace prefix with the original

如何使用XPath解决这样的名称空间?


非常感谢您的帮助。

答案似乎是XML在应该以xmlns:myns中的前缀声明名称空间的情况下重新声明了XMLNS。

来自www.w3.org:

The XML specification reserves all names beginning with the letters 'x', 'm', 'l' in any combination of upper- and lower-case for use by the W3C. To date three such names have been given definitions—although these names are not in the XML namespace, they are listed here as a convenience to readers and users:

  • xml:请参见http://www.w3.org/TR/xml/#NT-XMLDecl和http://www.w3.org/TR/xml-names/#xmlReserved
  • xmlns:请参阅http://www.w3.org/TR/xml-names/#ns-decl
  • xml-stylesheet:请参阅xml-stylesheet处理指令

这里有一些代码需要考虑。从代码开始创建Nokogiri :: XML :: Document:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
require 'nokogiri'

XML = <<EOT
    <?xml version="1.0" encoding="UTF-8"?>
    <CreateOrUpdateEventsRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dhamma.org" version="3-0-0">
       <LanguageKey>
        <IsoCode>en</IsoCode>
      </LanguageKey>
      <Publish>
        <Value>true</Value>
      </Publish>
      <Events>
        <Event>
          <EventKey>
            <LocationKey>
              <SubDomain>rasmi</SubDomain>
            </LocationKey>
            <EventId>10DayPDFStdTag</EventId>
          </EventKey>
        </Event>
      </Events>
       </LanguageKey>
    </CreateOrUpdateEventsRequest>
EOT


doc = Nokogiri::XML(XML)

这是根节点的名称:

1
doc.root.name # =>"CreateOrUpdateEventsRequest"

文档说:

When using CSS, if the namespace is called"xmlns", you can even omit the namespace name.

1
2
3
4
doc.at('CreateOrUpdateEventsRequest').name # =>"CreateOrUpdateEventsRequest"
doc.at('LanguageKey').to_xml # =>"<LanguageKey>\
        <IsoCode>en</IsoCode>\
      </LanguageKey>"

使用XPath,我们可以将默认名称空间指定为:

1
2
3
doc.at('//xmlns:LanguageKey').to_xml # =>"<LanguageKey>\
        <IsoCode>en</IsoCode>\
      </LanguageKey>"

有时,如果有很多命名空间,则使用collect_namespaces并将它们传递给它们是有意义的:

1
2
3
4
name_spaces = doc.collect_namespaces # =>
doc.at('//xmlns:LanguageKey', name_spaces).to_xml # =>"<LanguageKey>\
        <IsoCode>en</IsoCode>\
      </LanguageKey>"

您需要浏览Nokogiri :: XML :: Node的文档,以获取有关各种方法的更多信息。

我建议您首先尝试使用CSS选择器,以简化和简化XPath的可读性。我认为XPath具有更多功能,但有时会使我不知所措,因此我更喜欢CSS。


我不使用Nokogiri也不使用Ruby,
但是您需要为名称空间http://dhamma.org

注册前缀

当我阅读http://nokogiri.org/tutorials/searching_a_xml_html_document.html时
我了解您必须执行类似

的操作

1
$> @doc.xpath('//dha:LanguageKey', 'dha' => 'http://dhamma.org')