【问题标题】:Nokogiri : NoMethodError (undefined method `inner_html' for nil:NilClass)Nokogiri : NoMethodError (nil:NilClass 的未定义方法 `inner_html')
【发布时间】:2016-11-18 05:07:49
【问题描述】:

我正在尝试使用 nokogiri 解析简单的 XML 数据。 这是我的 XML:

POST /.... HTTP/1.1
Host: ....
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://...."

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="...." xmlns:xsd="...." xmlns:soap="....">
  <soap:Body>
    <WS_QueryOnSec xmlns="......">
      <type>string</type>
      <ID>string</ID>
    </WS_QueryOnSec>
  </soap:Body>
</soap:Envelope>

这是我的简单要求:

require "nokogiri"
@doc = Nokogiri::XML(request.body.read)
@something = @doc.at('type').inner_html

但是 Nokogiri 找不到类型或 ID 节点。 当我将数据更改为这个时,一切正常:

  <soap:Body>
      <type>string</type>
      <ID>string</ID>
  </soap:Body>

似乎问题在于上面的原始文本数据和带有xmlns或其他属性的点头! 你有什么建议来解决这个问题?

【问题讨论】:

  • 第一个“XML”不是 XML。它是包含 XML 的文本。将标题信息删除到空行。我认为阅读 XML 规范或阅读一些有关创建 XML 的教程会有所帮助。
  • @the Tin Man 但是这些标签中包含的属性呢?当我删除文本时,它仍然是一样的!直到我删除包含属性的整个标签!谢谢。

标签: ruby-on-rails ruby xml xml-parsing nokogiri


【解决方案1】:

第一个“XML”不是 XML。它是包含 XML 的文本。将标题信息删除到空白行,然后再试一次。

我认为阅读XML spec 或阅读一些有关创建 XML 的教程会帮助您了解它是如何定义的。 XML 是一个严格的规范,不允许有任何偏差。语法很灵活,但你必须遵守它的规则。

考虑以下示例:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
foo

<root>
  <node />
</root>
EOT

doc.errors # => [#<Nokogiri::XML::SyntaxError: Start tag expected, '<' not found>]

删除根标签之外的文本会导致正确的解析:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<root>
  <node />
</root>
EOT

doc.errors # => []

&lt;root&gt; 不一定是“根”节点的名称,它只是最外层的标签:

doc = Nokogiri::XML(<<EOT)
<foo>
  <node />
</foo>
EOT

doc.errors # => []

仍然会产生文档的有效 DOM/内部表示:

puts doc.to_html 

# >> <foo>
# >>   <node></node>
# >> </foo>

您的 XML 示例正在使用名称空间,这使事情有些复杂。 Nokogiri documentation 讨论了如何处理它们,因此您需要了解解析 XML 的那部分,因为您将再次遇到它。以下是使用它们的简单方法:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="utf-8"?>
<Envelope xmlns:xsi="...." xmlns:xsd="...." xmlns:soap="....">
  <Body>
    <WS_QueryOnSec xmlns="......">
      <type>string</type>
      <ID>string</ID>
    </WS_QueryOnSec>
  </Body>
</Envelope>
EOT

namespaces = doc.collect_namespaces

doc.at('type', namespaces).text # => "string"

【讨论】:

  • 谢谢@theTinMan。它绝对可以帮助了解结构。
  • 顺便问一下@the-tin-man 有没有办法在 Nogokiri 中从 xml 中拆分文本?
  • 这取决于你所说的“文本”和你的目标是什么。这确实是一个单独的问题,但请尝试使用doc.search('//text()').map(&amp;:text) 来了解您会发现什么。通常你想要比这更外科的东西。
猜你喜欢
  • 2013-11-14
  • 2013-01-14
  • 2017-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多