How to create an XML document with a namespaced root element with Nokogiri Builder

后端 未结 3 761
执笔经年
执笔经年 2020-12-15 09:02

I\'m implementing an exporter for XML data that requires namespaces. I\'m using Nokogiri\'s XML Builder (version 1.4.0) to do this, however, I can\'t get Nokogiri to create

相关标签:
3条回答
  • 2020-12-15 09:13
    require 'rubygems'
    require 'nokogiri'
    
    puts Nokogiri::XML::Builder.new do |xml| 
      xml.root("xmlns:foo"=>"url") do
        xml.parent.namespace = xml.parent.namespace_definitions.find{|ns|ns.prefix=="foo"}
        xml['foo'].child
      end
    end.to_xml
    

    You cannot use xml['foo'] before the namespace is defined, I.E. before you pass it as an argument to the root node, thus, the code above added the namespace after-the-fact to the root node.

    0 讨论(0)
  • 2020-12-15 09:20

    Three years after Luke's answer, it's gotten yet simpler. You can now use the namespace "before" it's defined. This code:

    require 'nokogiri'
    
    NAMESPACES = { 'xmlns:foo' => 'bar', 'xmlns:baz' => 'bat' }
    
    builder = Nokogiri::XML::Builder.new { |xml|
      xml['foo'].RootElement(NAMESPACES) {
        xml['baz'].FirstChild
      }
    }
    
    puts builder.to_xml
    

    Outputs this XML:

    <?xml version="1.0"?>
    <foo:RootElement xmlns:foo="bar" xmlns:baz="bat">
      <baz:FirstChild/>
    </foo:RootElement>
    
    0 讨论(0)
  • 2020-12-15 09:25

    Two years later, I found a cleaner way to do this by using Nokogiri::XML::Builder's document reference to retrieve the root node and add the namespace(s) to that. Like the previous solution, it requires the root node to exist before the namespaces can be added to it.

    I've changed the <root> element to <rootElement> so this is more clear:

    builder = Nokogiri::XML::Builder.new do |xml| 
      xml.rootElement do
        # create a namespace and save it for later
        ns = xml.doc.root.add_namespace_definition('foo', 'my-ns-url')
        # you can also create multiple name spaces
        xml.doc.root.add_namespace_definition('bar', 'http://example.com/bar')
    
        # assign the saved namespace to rootElement
        xml.doc.root.namespace = ns
    
        xml['foo'].child
        xml['bar'].child
      end
    end
    

    Now, builder.to_xml will return:

    <?xml version="1.0"?>
    <foo:rootElement xmlns:foo="my-ns-url" xmlns:bar="http://example.com/bar">
      <foo:child/>
      <bar:child/>
    </foo:rootElement>
    

    I like this better because you don't have to search for the name space, and it's easier to add multiple namespaces.

    0 讨论(0)
提交回复
热议问题