views:

431

answers:

1

I need to add an element to an existing XML document which uses a namespace that doesn't exist in the original. How do I do this?

Ideally I would like to use REXML for portability, but any common XML library would be okay. An ideal solution would be smart about namespace collisions.

I have an xml document which looks like this:

<xrds:XRDS
 xmlns:xrds="xri://$xrds"
 xmlns="xri://$xrd*($v*2.0)">
    <XRD>
        <Service>
            <Type>http://specs.openid.net/auth/2.0/signon&lt;/Type&gt;
            <URI>http://provider.openid.example/server/2.0&lt;/URI&gt;
        </Service>
    </XRD>
</xrds:XRDS>

and add:

<Service
 xmlns="xri://$xrd*($v*2.0)"
 xmlns:openid="http://openid.net/xmlns/1.0"&gt;
    <Type>http://openid.net/signon/1.0&lt;/Type&gt;
    <URI>http://provider.openid.example/server/1.0&lt;/URI&gt;
    <openid:Delegate>http://example.openid.example&lt;/openid:Delegate&gt;
</Service>

Yielding something equivalent to:

<xrds:XRDS
 xmlns:xrds="xri://$xrds"
 xmlns="xri://$xrd*($v*2.0)"
 xmlns:openid="http://openid.net/xmlns/1.0"&gt;
    <XRD>
        <Service>
            <Type>http://specs.openid.net/auth/2.0/signon&lt;/Type&gt;
            <URI>http://provider.openid.example/server/2.0&lt;/URI&gt;
        </Service>
        <Service>
            <Type>http://openid.net/signon/1.0&lt;/Type&gt;
            <URI>http://provider.openid.example/server/1.0&lt;/URI&gt;
            <openid:Delegate>http://example.openid.example&lt;/openid:Delegate&gt;
        </Service>
    </XRD>
</xrds:XRDS>
A: 

It turns out this is a dumb question. If both the initial document and the element to be added are internally consistent, then namespaces are okay. So this is equivalent to the final document:

<xrds:XRDS
 xmlns:xrds="xri://$xrds"
 xmlns="xri://$xrd*($v*2.0)">
    <XRD>
        <Service>
            <Type>http://specs.openid.net/auth/2.0/signon&lt;/Type&gt;
            <URI>http://provider.openid.example/server/2.0&lt;/URI&gt;
        </Service>
        <Service
         xmlns:openid="http://openid.net/xmlns/1.0" 
         xmlns="xri://$xrd*($v*2.0)">
            <Type>http://openid.net/signon/1.0&lt;/Type&gt;
            <URI>http://provider.openid.example/server/1.0&lt;/URI&gt;
            <openid:Delegate>http://example.openid.example&lt;/openid:Delegate&gt;
        </Service>
    </XRD>
</xrds:XRDS>

It is important that both the initial document and the element define a default namespace with the xmlns attribute.

Assume the initial document is in initial.xml, and the element is in element.xml. To create this final document with REXML, simply:

require 'rexml/document'
include REXML

document = Document.new(File.new('initial.xml'))
unless document.root.attributes['xmlns']
  raise "No default namespace in initial document" 
end
element = Document.new(File.new('element.xml'))
unless element.root.attributes['xmlns']
  raise "No default namespace in element" 
end

xrd = document.root.elements['XRD']
xrd.elements << element
document
Joseph Holsten