Nokogiri: создать xml из строки с `?` в имени поля

Ответ контроллера включает "spec?" поле:

r = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash type=\"array\">\n  <item><spec? type=\"boolean\">false</spec?>\n </item>\n  <hash>\n"

При попытке создать из него xml с помощью Nokogiri.xml(r) получаем буквально:

<?xml version="1.0" encoding="UTF-8"?>
<hash type="array">
  <item><spec type=" type=&quot;boolean&quot;&gt;false/spec">
 </spec>item&gt;
  <hash>
</hash></item></hash>

что-то странное;

Мой вопрос: возможно ли создать xml из строки с помощью Nokogiri, анализируя или удаляя ? и другие символы, не соответствующие стандарту xml, на этапе Nokogiri.XML()?

Желаемый результат:

Nokogiri.xml(r) do |config|
 config.maybe_some_configs?
end #=>
    <?xml version="1.0" encoding="UTF-8"?>
    <hash type="array">
      <item><spec type="boolean">false</spec></item>       
    </hash>

person ted    schedule 20.03.2013    source источник


Ответы (1)


Правильный способ анализа строки в XML DOM — это Nokogiri::XML, Nokogiri.XML или Nokogiri::XML.parse, но не использование xml.

Кроме того, теги XML не могут содержать ?. Дополнительную информацию см. в спецификации. Вам придется покопаться в разделе «Имена и токены» и расшифровать описания шестнадцатеричных символов, чтобы выяснить допустимые диапазоны символов, но подсказка заключается в том, что ? — это код символа 0x3f.

Что приводит к тому, что XML в r недействителен:

<?xml version="1.0" encoding="UTF-8"?>
<hash type="array">
  <item><spec? type="boolean">false</spec?>
 </item>
  <hash>

Что при анализе приводит к:

irb(main):012:0> doc = Nokogiri::XML(r)
#<Nokogiri::XML::Document:0x80c8014c name="document" children=[#<Nokogiri::XML::Element:0x80c7399c name="hash" attributes=[#<Nokogiri::XML::Attr:0x80c733e8 name="type" value="array">] children=[#<Nokogiri::XML::Text:0x80c6e26c "\n  ">, #<Nokogiri::XML::Element:0x80c6df60 name="item" children=[#<Nokogiri::XML::Element:0x80c6d970 name="spec">, #<Nokogiri::XML::Text:0x80c6d09c "? type=\"boolean\">false">]>, #<Nokogiri::XML::Text:0x80c6ca34 "?>\n ">]>]>
irb(main):013:0> doc.errors
[
    [0] #<Nokogiri::XML::SyntaxError: error parsing attribute name>,
    [1] #<Nokogiri::XML::SyntaxError: attributes construct error>,
    [2] #<Nokogiri::XML::SyntaxError: Couldn't find end of Start Tag spec line 3>,
    [3] #<Nokogiri::XML::SyntaxError: expected '>'>,
    [4] #<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: item line 3 and spec>,
    [5] #<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: hash line 2 and item>,
    [6] #<Nokogiri::XML::SyntaxError: Extra content at the end of the document>
]

В результате Нокогири приходится исправлять DOM, чтобы попытаться разобраться в этом. Результирующий XML выглядит так:

irb(main):014:0> puts doc.to_xml
<?xml version="1.0" encoding="UTF-8"?>
<hash type="array">
  <item><spec/>? type="boolean"&gt;false</item>?&gt;
 </hash>

Чтобы это исправить, нужно передать Nokogiri действительный XML. Либо исправьте источник XML, если вы его контролируете, либо исправьте ошибки в строке, прежде чем передавать ее в Nokogiri.

По своему определению XML является строгим форматом, и Nokogiri соблюдает это и, стараясь быть дружелюбным, позволяет вам проверить errors, чтобы убедиться, что это empty?. Если это не так, велики шансы, что вам не следует продолжать использовать источник, пока вы не определите проблемы и не исправите все, что вызывает проблемы синтаксического анализа. Иногда проблема довольно безобидна, и вы можете игнорировать ее, но в любом случае вы должны, по крайней мере, осознавать ее.

Предварительно массировать данные до того, как Нокогири их увидит, несложно:

doc = Nokogiri::XML(r.gsub('spec?', 'spec'))

irb(main):024:0> puts doc.to_xml
<?xml version="1.0" encoding="UTF-8"?>
<hash type="array">
  <item><spec type="boolean">false</spec>
 </item>
  <hash>
</hash></hash>
nil
irb(main):025:0> doc.errors
[
    [0] #<Nokogiri::XML::SyntaxError: Premature end of data in tag hash line 5>,
    [1] #<Nokogiri::XML::SyntaxError: Premature end of data in tag hash line 2>
]

Это начало, но не попытка исправить это за вас полностью. Я учу тебя ловить рыбу, а не раздаю рыбу.

person the Tin Man    schedule 20.03.2013