Как кормить только нокогири струной - PullRequest
1 голос
/ 09 декабря 2010

У меня есть следующий образец XML:

<all>
    <houses>
        <reg info='<root><h level="2" i="1"> something </h><root>' 
             other="test"
             something
        </reg>
    </houses>
</all>

Я хочу проанализировать XML, предоставленный в свойстве info тега <reg>, но не знаю, как передать содержимое атрибута info в Nokogiri.

Вот что у меня сейчас:

doc = Nokogiri::HTML(open-uri(mylink))
node = doc.xpath(//houses/reg)
puts node[0]['info'].class  #string
#content of info property as string. This is what I want to feed to nokogiri as xml
puts node[0]['info'].text   

Как я могу это сделать?

Ответы [ 5 ]

3 голосов
/ 09 декабря 2010

Вам нужно получить текст атрибута info и использовать класс GCI для удаления HTML-кода.Затем вы можете передать строку в Nokogiri::HTML, и она будет проанализирована.Как то так.

require "nokogiri"
require "open-uri"
require "cgi"

doc = Nokogiri::HTML(open-uri("http://example.com/foo.xml"))
node = doc.xpath("//houses/reg")
info_string = CGI.unescapeHTML(node[0]['info'])
info_doc = Nokogiri::XML(info_string)
# Now you can have a Nokogiri document from that attribute.
0 голосов
/ 04 июня 2016

Вот несколько замечаний:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<all>
  <houses>
    <reg info='<root><h level="2" i="1"> something </h><root>' 
          other="test"
          something
    </reg>
  </houses>
</all>
EOT

doc.errors  # => [#<Nokogiri::XML::SyntaxError: Unescaped '<' not allowed in attributes values>, #<Nokogiri::XML::SyntaxError: attributes construct error>, #<Nokogiri::XML::SyntaxError: Couldn't find end of Start Tag reg line 3>, #<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: root line 3 and reg>, #<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: root line 3 and houses>, #<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: houses line 2 and all>, #<Nokogiri::XML::SyntaxError: Premature end of data in tag all line 1>]
doc.at('reg')['info'] # => ""
puts doc.to_xml

# >> <?xml version="1.0"?>
# >> <all>
# >>   <houses>
# >>     <reg info=""/><root><h level="2" i="1"> something </h><root>' 
# >>           other="test"
# >>           something
# >>     </root>
# >>   </root>
# >> </houses>
# >> </all>

При синтаксическом анализе XML обычно следует использовать Nokogiri::XML, поскольку XML является строгой спецификацией.Эта разметка искажена, и Nokogiri правильно помечает ошибки, и, поскольку она искажена, попытается исправить ее и продолжить анализ.

Использование Nokogiri::HTML ослабляет узды и позволяет анализатору быть более снисходительным в отношении того, чтоэто видит;HTML, как известно, плохо написан, поэтому Nokogiri пытается быть более любезным:

doc = Nokogiri::HTML(<<EOT)
<all>
  <houses>
    <reg info='<root><h level="2" i="1"> something </h><root>' 
          other="test"
          something
    </reg>
  </houses>
</all>
EOT

doc.errors  # => [#<Nokogiri::XML::SyntaxError: Tag all invalid>, #<Nokogiri::XML::SyntaxError: Tag houses invalid>, #<Nokogiri::XML::SyntaxError: error parsing attribute name>, #<Nokogiri::XML::SyntaxError: Tag reg invalid>]
doc.at('reg')['info'] # => "<root><h level=\"2\" i=\"1\"> something </h><root>"
puts doc.to_xml


# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html><body>
# >> <all>
# >>   <houses>
# >>     <reg info='&lt;root&gt;&lt;h level="2" i="1"&gt; something &lt;/h&gt;&lt;root&gt;' other="test" something>
# >>   </reg></houses>
# >> </all>
# >> </body></html>

Обратите внимание, как Nokogiri теперь:

  • правильно HTML закодировал содержание info
  • правильно извлекает и декодирует содержимое для info.
  • обернуло XML в теги HTML <html><body> из-за синтаксического анализа содержимого как HTML.

Чтобы извлечь фиксированный XMLтребуется откинуть пару слоев:

puts doc.at('all').to_xml

# >> <all>
# >>   <houses>
# >>     <reg info="&lt;root&gt;&lt;h level=&quot;2&quot; i=&quot;1&quot;&gt; something &lt;/h&gt;&lt;root&gt;" other="test" something="">
# >>   </reg></houses>
# >> </all>

Я не уверен, изменилось ли поведение Нокогири с тех пор, как вопрос был задан изначально, но текущее поведение в v.1.6.7.2 правильно обрабатывает декодирование без необходимости использованияCGI.

0 голосов
/ 03 июня 2016

Вот несколько замечаний:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<all>
  <houses>
    <reg info='<root><h level="2" i="1"> something </h><root>' 
          other="test"
          something
    </reg>
  </houses>
</all>
EOT

doc.errors  # => [#<Nokogiri::XML::SyntaxError: Unescaped '<' not allowed in attributes values>, #<Nokogiri::XML::SyntaxError: attributes construct error>, #<Nokogiri::XML::SyntaxError: Couldn't find end of Start Tag reg line 3>, #<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: root line 3 and reg>, #<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: root line 3 and houses>, #<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: houses line 2 and all>, #<Nokogiri::XML::SyntaxError: Premature end of data in tag all line 1>]
doc.at('reg')['info'] # => ""
puts doc.to_xml

# >> <?xml version="1.0"?>
# >> <all>
# >>   <houses>
# >>     <reg info=""/><root><h level="2" i="1"> something </h><root>' 
# >>           other="test"
# >>           something
# >>     </root>
# >>   </root>
# >> </houses>
# >> </all>

При синтаксическом анализе XML обычно следует использовать Nokogiri::XML, поскольку XML является строгой спецификацией.Эта разметка искажена, и Nokogiri правильно помечает ошибки, и, поскольку она искажена, попытается исправить ее и продолжить анализ.

Использование Nokogiri::HTML ослабляет узды и позволяет анализатору быть более снисходительным в отношении того, чтоэто видит;HTML, как известно, плохо написан, поэтому Nokogiri пытается быть более любезным:

doc = Nokogiri::HTML(<<EOT)
<all>
  <houses>
    <reg info='<root><h level="2" i="1"> something </h><root>' 
          other="test"
          something
    </reg>
  </houses>
</all>
EOT

doc.errors  # => [#<Nokogiri::XML::SyntaxError: Tag all invalid>, #<Nokogiri::XML::SyntaxError: Tag houses invalid>, #<Nokogiri::XML::SyntaxError: error parsing attribute name>, #<Nokogiri::XML::SyntaxError: Tag reg invalid>]
doc.at('reg')['info'] # => "<root><h level=\"2\" i=\"1\"> something </h><root>"
puts doc.to_xml


# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html><body>
# >> <all>
# >>   <houses>
# >>     <reg info='&lt;root&gt;&lt;h level="2" i="1"&gt; something &lt;/h&gt;&lt;root&gt;' other="test" something>
# >>   </reg></houses>
# >> </all>
# >> </body></html>

Обратите внимание, как Nokogiri теперь:

  • правильно HTML закодировал содержание info
  • правильно извлекает и декодирует содержимое для info.

Я не уверен, изменилось ли поведение Нокогири с тех пор, как вопрос был задан изначально, но текущее поведение в v.1.6.7.2 обрабатывает декодированиеправильно, без необходимости использовать CGI.

0 голосов
/ 09 мая 2012

node[0].attr('info') дает значение атрибута info

0 голосов
/ 09 декабря 2010
require 'nokogiri'

xml = "<all>
    <houses>
        <reg info='<root><h level=\"2\" i=\"1\"> something </h><root>' 
             other=\"test\"
             something
        </reg>
    </houses>
</all>"

doc = Nokogiri::HTML(xml)
node = doc.xpath('//houses/reg')
puts node[0]['info'].class  #string
puts node[0]['info']

inner_xml = node[0]['info']
inner_doc = Nokogiri::XML(inner_xml)
puts inner_doc.xpath('root/h')[0].text
...