tags:

views:

1212

answers:

3

I have two XML files with two different XSD schemas and different namespaces. They have both an identical substructure. And now i need to copy that node (and all childs) from one XML document to the other one.

Clone would do, if the namespaces were the same. Is there a nice way to do it? (The substructure will change later on - but will be kept identical.)

+3  A: 

Basically, you need an XSL transformation that creates new elements with equal names, but a different namespace.

Consider the following input XML:

<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://tempuri.org/ns_old"&gt;
    <child attrib="value">text</child>
</test>

Now you need a template that says "copy structure and name of everything you see, but declare a new namespace while you're at it":

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:old="http://tempuri.org/ns_old"
>
  <xsl:output method="xml" version="1.0" 
    encoding="UTF-8" indent="yes" omit-xml-declaration="no" 
  />

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="old:*">
    <xsl:element name="{local-name()}" namespace="http://tempuri.org/ns_new"&gt;
      <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

When you run the above XML through it, this produces:

<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://tempuri.org/ns_new"&gt;
  <child attrib="value">text</child>
</test>

All your http://tempuri.org/ns_old elements have effectively changed their namespace. When your input XML has more than one namespace at the same time, the XSL must most likely be extended a bit.

Tomalak
A: 

Not sure if this applies, but I've done something similar working with two xml docs in vb.net:

Private Shared Sub CopyElement(ByVal FromE As Xml.XmlElement, ByVal ToE As Xml.XmlElement)
    CopyElement(FromE, ToE, Nothing)
End Sub
Private Shared Sub CopyElement(ByVal FromE As Xml.XmlElement, ByVal ToE As Xml.XmlElement, ByVal overAttr As Xml.XmlAttributeCollection)
    Dim NewE As Xml.XmlElement
    Dim e As Xml.XmlElement
    NewE = ToE.OwnerDocument.CreateElement(FromE.Name)

    CopyAttributes(FromE, NewE)
    If Not overAttr Is Nothing Then
        OverrideAttributes(overAttr, NewE)
    End If
    For Each e In FromE
        CopyElement(e, NewE, overAttr)
    Next
    ToE.AppendChild(NewE)


End Sub
Private Shared Sub CopyAttributes(ByVal FromE As Xml.XmlElement, ByVal ToE As Xml.XmlElement)
    Dim a As Xml.XmlAttribute
    For Each a In FromE.Attributes
        ToE.SetAttribute(a.Name, a.Value)
    Next
End Sub
Private Shared Sub OverrideAttributes(ByVal AC As Xml.XmlAttributeCollection, ByVal E As Xml.XmlElement)
    Dim a As Xml.XmlAttribute
    For Each a In AC
        If Not E.Attributes.ItemOf(a.Name) Is Nothing Then
            E.SetAttribute(a.Name, a.Value)
        End If
    Next
End Sub
steve
A: 

Following Tomalak's example(with a little fix), but use SetAttribute + OuterXml + InnerXml is much more simple const string xml_str = @"

<?xml version='1.0' encoding='UTF-8'?>
<root>
  <test xmlns='http://tempuri.org/ns_old'>
    <child attrib='value'>text</child>
  </test>
</root>";

";

public static void RunSnippet()

{

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml_str);

    XmlElement elem = doc.DocumentElement["test"];
    WL( string.Format("[{0}]", elem ) );
    elem.SetAttribute("xmlns", "http://another.namespace.org/");
    WL( elem.OuterXml );

    XmlDocument another_doc = new XmlDocument();
    another_doc.LoadXml("<root/>");
    another_doc.DocumentElement.InnerXml = elem.OuterXml;
    WL( another_doc.DocumentElement.OuterXml );

}

赵如飞