Nokogiri没有在ruby中解析XML - xmlns问题?

dwk*_*kns 2 ruby xml web-services nokogiri

鉴于以下ruby代码:

require 'nokogiri'

xml = "<?xml version='1.0' encoding='UTF-8'?>
<ProgramList xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns='http://publisher.webservices.affili.net/'>
  <TotalRecords>145</TotalRecords>
  <Programs>
    <ProgramSummary>
      <ProgramID>6540</ProgramID>
      <Title>Matalan</Title>
      <Limitations>A bit of text
      </Limitations>
      <URL>http://www.matalan.co.uk</URL>
      <ScreenshotURL>http://www.matalan.co.uk/</ScreenshotURL>
      <LaunchDate>2009-11-02T00:00:00</LaunchDate>
      <Status>1</Status>
    </ProgramSummary>
    <ProgramSummary>
      <ProgramID>11787</ProgramID>
      <Title>Club 18-30</Title>
      <Limitations/>
      <URL>http://www.club18-30.com/</URL>
      <ScreenshotURL>http://www.club18-30.com</ScreenshotURL>
      <LaunchDate>2013-05-16T00:00:00</LaunchDate>
      <Status>1</Status>
    </ProgramSummary>
  </Programs>
</ProgramList>"

doc = Nokogiri::XML(xml)
p doc.xpath("//Programs")
Run Code Online (Sandbox Code Playgroud)

给出:

=> []
Run Code Online (Sandbox Code Playgroud)

不是预期的.

进一步调查,如果我xmlns='http://publisher.webservices.affili.net/'从初始<ProgramList>标签中删除,我得到预期的输出.

事实上,如果我改变xmlns='http://publisher.webservices.affili.net/',xmlns:anything='http://publisher.webservices.affili.net/'我得到预期的输出.

所以我的问题是这里发生了什么?这是格式错误的XML吗?处理它的最佳策略是什么?

虽然在这个例子中它是硬编码的,但XML(将来自)来自Web服务.

更新

我意识到我可以使用这种remove_namespaces!方法,但Nokogiri文档确实说它是这样"...probably is not a good thing in general"做的.此外,我对它为什么会发生以及"正确的"XML应该是什么感兴趣.

mat*_*att 5

xmlns='http://publisher.webservices.affili.net/'指示出现的所有元素下的所有元素的默认命名空间(包括元素本身).这意味着所有没有显式名称空间的元素都属于此命名空间.

XPath查询没有默认名称空间(至少在XPath 1.0中),因此任何没有前缀的名称都会引用没有名称空间的元素.

在您的代码中,您希望Programhttp://publisher.webservices.affili.net/命名空间中找到元素(因为这是默认命名空间),但是在(在您的XPath查询中)查找命名空间中的Program元素.

在查询中显式指定命名空间,您可以执行以下操作:

doc.xpath("//pub:Programs", "pub" => "http://publisher.webservices.affili.net/")
Run Code Online (Sandbox Code Playgroud)

Nokogiri使得在根元素上声明的命名空间(如本例中)更容易,并使用相同的前缀为您声明它们.它还将使用xmlns前缀声明默认命名空间,因此您还可以执行以下操作:

doc.xpath("//xmlns:Programs")
Run Code Online (Sandbox Code Playgroud)

这将给你相同的结果.