Получение ActiveRecord (Rails) to_xml для использования xsi: nil и xsi: type вместо nil и type - PullRequest
0 голосов
/ 14 апреля 2010

Поведение по умолчанию сериализации XML (to_xml) для объектов ActiveRecord будет создавать атрибуты 'type' и 'nil', которые похожи на атрибуты экземпляра схемы XML, но не заданы в пространстве имен XML.

Например, модель может выдать вывод, подобный следующему:

<user>
  <username nil="true" />
  <first-name type="string">Name</first-name>
</user>

Есть ли способ получить to_xml для использования пространства имен экземпляра схемы XML и префикса атрибутов и значений?

ИспользованиеВ приведенном выше примере я хотел бы получить следующее:

<user xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xs="http://www.w3.org/1999/XMLSchema">
  <username xsi:nil="true" />
  <first-name xsi:type="xs:string">Name</first-name>
</user>

Ответы [ 2 ]

2 голосов
/ 22 июля 2012

У меня были аналогичные требования, и я вместо этого выбрал подкласс :: Builder :: XmlMarkup:

require 'builder/xmlmarkup'

class MyXmlMarkup < ::Builder::XmlMarkup
  def tag!(sym, *args, &block)
    if @level == 0 # Root element
      args << {"xmlns" => "http://my_company.com/api/schemas/xml",
               "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance"}
    end

    if args[:nil] = true
      args << {"xsi:nil" => true}
    end

    super(sym, *args, &block)
  end
end

тогда вы можете использовать его с:

foo.to_xml(builder: MyXmlMarkup.new(indent: 2))
1 голос
/ 15 апреля 2010

Я столкнулся с чем-то похожим, но при вызове #to_xml в Hash, а не в экземпляре AR.

Я придумал этого помощника:

  #
  # Returns a new Builder::XmlMarkup that'll handle API's to_xml needs
  # Usually you don't need to construct a builder, as to_xml will create one
  # however we need some things modified (adding a namespace, XSD-nillable-compliant-nils
  # and to_xml is too braindead to allow us to alter such behaviors externally
  #
  def api_new_xml_builder
    builder = Builder::XmlMarkup.new(:indent => 2)
    class << builder
      def method_missing(*args, &block)
        @api_seen ||= 0
        @api_seen += 1
        if @api_seen == 1
          # Root element. Needs some decoration
          args[1] ||= {}
          args[1]["xmlns"] = "http://my_company.com/api/schemas/xml"
          args[1]["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
        end
        if args[2].is_a?(Hash) && args[2][:nil] == true
          args[2]["xsi:nil"] = true
        end
        super(*args, &block)
      end
    end
    builder
  end

Затем используется так:

builder = api_new_xml_builder
foo.to_xml(:builder => builder)

Обратите внимание, что я решил оставить существующие атрибуты nil = и type = и добавить свой собственный префикс xsi nil, однако вместо этого заменить их тривиально.

...