2010-12-09 4 views
1

У меня есть следующий пример XML:Как кормить только строку Nokogiri

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

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

Это то, что я сейчас:

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 

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

+0

Обычно использование парсера HTML для анализа XML было бы неправильным, но в этом случае это помогает, поскольку разбор HTML более мягкий. См. Мой ответ на текущее поведение Нокогири. – 2016-06-03 20:14:22

ответ

3

Вам нужно получить текст атрибута info и использовать класс GCI для unescape 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
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 
-1

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

+0

Этот код ничего не сделает без синтаксического анализа, а неправильный синтаксический анализ приведет к искажению атрибута `info`. Ваш ответ должен показать, как сделать работоспособное решение. – 2016-06-03 20:04:19

0

Вот некоторые вещи, чтобы отметить:

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

Вот некоторые вещи, чтобы отметить:

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> 

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

Смежные вопросы