Добавление пространства имен с помощью Nokogiri's XML Builder - PullRequest
5 голосов
/ 04 ноября 2011

Я несколько часов ломал голову, но никак не могу определить, как добавить пространство имен XMLNS, используя класс Nokogiri XML Builder для создания структуры XML.

Например, рассмотрим пример XML ниже: я могу создать все между тегами GetQuote, но создание «p: ACMRequest» остается загадкой.

Я сталкивался с этой ссылкой, https://gist.github.com/428455/7a15f84cc08c05b73fcec2af49947d458ae3b96a,, которая все еще не имеет смысла для меня. Даже со ссылкой на документацию XML, http://www.w3.org/TR/xml-names/, тоже не имело особого смысла.

<?xml version="1.0" encoding="UTF-8"?>
<p:ACMRequest xmlns:p="http://www.acme.com" xmlns:p1="http://www.acme.com/datatypes" xmlns:p2="http://www.acme.com/ACMRequestdatatypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.acme.com ACM-req.xsd ">
  <GetQuote>
    <Request>
      <ServiceHeader>
        ...
        ...
      </ServiceHeader>
    </Request>
    <From>
      ...
      ...
    </From>
    <Details>
      ...
      ...
    </Details>
  </GetQuote>
</p:ACMRequest>

Ответы [ 2 ]

14 голосов
/ 04 ноября 2011

Если вы используете Google для "пространства имен nokogiri xml builder" , то первым попаданием будет страница документации Nokogiri с надписью:

Пространства имен добавляются аналогично атрибутам. Nokogiri::XML::Builder предполагает, что когда атрибут начинается с «xmlns», он должен быть пространством имен:

   builder = Nokogiri::XML::Builder.new { |xml|
     xml.root('xmlns' => 'default', 'xmlns:foo' => 'bar') do
       xml.tenderlove
     end
   }
   puts builder.to_xml

Будет выводить XML следующим образом:

   <?xml version="1.0"?>
   <root xmlns:foo="bar" xmlns="default">
     <tenderlove/>
   </root>

Применяя это к вашему конкретному вопросу, просто сделайте:

require 'nokogiri'
NS = {
  "xmlns:p"   => "http://www.acme.com",
  "xmlns:p1"  => "http://www.acme.com/datatypes",
  "xmlns:p2"  => "http://www.acme.com/ACMRequestdatatypes",
  "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
}
builder = Nokogiri::XML::Builder.new { |xml|
  xml.ACMRequest(NS) do
    xml.GetQuote
  end
}
puts builder.to_xml

#=> <?xml version="1.0"?>
#=> <ACMRequest xmlns:p="http://www.acme.com" xmlns:p1="http://www.acme.com/datatypes" xmlns:p2="http://www.acme.com/ACMRequestdatatypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
#=>   <GetQuote/>
#=> </ACMRequest>

Что касается префикса пространства имен для самого корневого элемента ...

<p:ACMRequest xmlns:p="…">…</p:ACMRequest>

… Я не могу понять, как применить префикс пространства имен к первому элементу в Нокогири во время создания. Вместо этого вы должны применить пространство имен после создания документа:

root = builder.doc.root
acme = root.namespace_definitions.find{ |ns| ns.href==NS["xmlns:p"] }
root.namespace = acme
puts builder.to_xml

#=> <?xml version="1.0"?>
#=> <p:ACMRequest xmlns:p="http://www.acme.com" xmlns:p1="http://www.acme.com/datatypes" xmlns:p2="http://www.acme.com/ACMRequestdatatypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">atypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
#=>   <GetQuote/>
#=> </p:ACMRequest>

Кроме того, вы можете обмануть:

# This happens to work for now, but I doubt you should rely upon it.
builder.doc.root.name = "p:ACMRequest"

Per " Создание XML-документа с корневым элементом в пространстве имен с помощью Nokogiri builder ", вы можете сделать это во время создания с помощью небольшого хака:

builder = Nokogiri::XML::Builder.new { |xml|
  xml.ACMRequest(NS) do
   xml.parent.namespace = … # find the ns in xml.parent.namespace_definitions
   # …
  end
end
12 голосов
/ 26 июля 2013
require 'nokogiri'
NS = {
  "xmlns:p"   => "http://www.acme.com",
  "xmlns:p1"  => "http://www.acme.com/datatypes",
  "xmlns:p2"  => "http://www.acme.com/ACMRequestdatatypes",
  "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
}
builder = Nokogiri::XML::Builder.new { |xml|
  xml['p'].ACMRequest(NS) do
    xml.GetQuote
  end
}
puts builder.to_xml

Производит:

<?xml version="1.0"?>
<p:ACMRequest xmlns:p="http://www.acme.com" xmlns:p1="http://www.acme.com/datatypes" xmlns:p2="http://www.acme.com/ACMRequestdatatypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <p:GetQuote/>
</p:ACMRequest>

Это задокументировано в API построителя: http://nokogiri.org/Nokogiri/XML/Builder.html:

Ссылка на объявленные пространства имен

Теги, которые ссылаются на пространства имен не по умолчанию (то есть тег «foo: bar») могут быть построенным с использованием метода Nokogiri :: XML :: Builder # [].

...