如何将节点结构从一个xml复制到另一个具有不同命名空间的节点?

时间:2023-01-14 08:12:00

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.

我有两个XML文件,有两个不同的XSD架构和不同的命名空间。它们具有相同的子结构。现在我需要将该节点(以及所有子节点)从一个XML文档复制到另一个XML文档。

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.)

如果命名空间相同,克隆就会这样做。有一个很好的方法吗? (子结构将在稍后改变 - 但将保持相同。)

4 个解决方案

#1


3  

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

基本上,您需要一个XSL转换,它创建具有相同名称但具有不同命名空间的新元素。

Consider the following input XML:

考虑以下输入XML:

<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://tempuri.org/ns_old">
    <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">
      <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

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

通过它运行上面的XML时,会产生:

<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://tempuri.org/ns_new">
  <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.

您的所有http://tempuri.org/ns_old元素都有效地更改了其命名空间。当您的输入XML同时具有多个命名空间时,XSL最有可能被扩展一点。

#2


0  

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

不确定这是否适用,但我已经做了类似的工作与vb.net中的两个xml文档:

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

#3


0  

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

按照Tomalak的例子(稍加修复),但使用SetAttribute + OuterXml + InnerXml更简单的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 );

}

#4


0  

In case you wish to copy all the sub elements of a node on matching of some attribute. You can just copy the InnerXML of referenced node and set it equal to new node.

如果您希望在匹配某些属性时复制节点的所有子元素。您只需复制引用节点的InnerXML并将其设置为等于新节点即可。

Something like this, below, I have a XML block with Document Element or Root element as Tablist, I need to add new node under Tablist with Role="Ka" and all the sub nodes of Ka should be same as XXX:

下面这样的东西,我有一个带有Document Element或Root元素的XML块作为Tablist,我需要在Tablist下添加Role =“Ka”的新节点,Ka的所有子节点应该与XXX相同:

<Tablist>
    <Designation Role="XXX">
        <!--<Tab name="x" default="x"/>-->
        <!--<Tab name="y" default="y"/>-->
        <Tab name="r" default="r" />
        <Tab name="rd" default="rd" />
        <Tab name="qq" default="qq" />
        <Tab name="ddd" default="ddd" />
      </Designation>
    <Designation Role="YYY">
        <!--<Tab name="a" default="a"/>-->
        <!--<Tab name="b" default="b"/>-->
        <Tab name="c" default="c" />
        <Tab name="dd" default="dd" />
        <Tab name="ee" default="ee" />
        <Tab name="f" default="f" />
      </Designation>
    </Tablist>

So I just write following code:

所以我只写下面的代码:

XmlDocument objXmlDocument1 = null;
objXmlDocument1 = new XmlDocument();
objXmlDocument1.Load(
    System.Web.HttpContext.Current.Server.MapPath("") + 
    "\\XMLSchema\\" + 
    "ABC.xml");

XMLNodesList nodes1 = objXmlDocument1.GetElementsByTagName("Designation");
foreach (XmlNode n in nodes1) {
    if (n.Attributes["Role"].Value.Trim().Equals("XXX"){                                
        objnode1 = n;
        break;
    }
}
if (objnode1 != null){
    XmlNodeList innerNodes1 = objnode1.ChildNodes;
    XmlNode newNode1 = objXmlDocument1.CreateElement("Designation");
    XmlAttribute newAtt1 = objXmlDocument1.CreateAttribute("Role");
    newAtt1.Value = "Ka";
    newNode1.Attributes.Append(newAtt1);
    newNode1.InnerXml=objnode1.InnerXml;
    objXmlDocument1.DocumentElement.AppendChild(newNode1);
}
objXmlDocument1.Save(
    System.Web.HttpContext.Current.Server.MapPath("") + 
    "\\XMLSchema\\" + 
    "ABC.xml");

#1


3  

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

基本上,您需要一个XSL转换,它创建具有相同名称但具有不同命名空间的新元素。

Consider the following input XML:

考虑以下输入XML:

<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://tempuri.org/ns_old">
    <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">
      <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

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

通过它运行上面的XML时,会产生:

<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://tempuri.org/ns_new">
  <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.

您的所有http://tempuri.org/ns_old元素都有效地更改了其命名空间。当您的输入XML同时具有多个命名空间时,XSL最有可能被扩展一点。

#2


0  

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

不确定这是否适用,但我已经做了类似的工作与vb.net中的两个xml文档:

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

#3


0  

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

按照Tomalak的例子(稍加修复),但使用SetAttribute + OuterXml + InnerXml更简单的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 );

}

#4


0  

In case you wish to copy all the sub elements of a node on matching of some attribute. You can just copy the InnerXML of referenced node and set it equal to new node.

如果您希望在匹配某些属性时复制节点的所有子元素。您只需复制引用节点的InnerXML并将其设置为等于新节点即可。

Something like this, below, I have a XML block with Document Element or Root element as Tablist, I need to add new node under Tablist with Role="Ka" and all the sub nodes of Ka should be same as XXX:

下面这样的东西,我有一个带有Document Element或Root元素的XML块作为Tablist,我需要在Tablist下添加Role =“Ka”的新节点,Ka的所有子节点应该与XXX相同:

<Tablist>
    <Designation Role="XXX">
        <!--<Tab name="x" default="x"/>-->
        <!--<Tab name="y" default="y"/>-->
        <Tab name="r" default="r" />
        <Tab name="rd" default="rd" />
        <Tab name="qq" default="qq" />
        <Tab name="ddd" default="ddd" />
      </Designation>
    <Designation Role="YYY">
        <!--<Tab name="a" default="a"/>-->
        <!--<Tab name="b" default="b"/>-->
        <Tab name="c" default="c" />
        <Tab name="dd" default="dd" />
        <Tab name="ee" default="ee" />
        <Tab name="f" default="f" />
      </Designation>
    </Tablist>

So I just write following code:

所以我只写下面的代码:

XmlDocument objXmlDocument1 = null;
objXmlDocument1 = new XmlDocument();
objXmlDocument1.Load(
    System.Web.HttpContext.Current.Server.MapPath("") + 
    "\\XMLSchema\\" + 
    "ABC.xml");

XMLNodesList nodes1 = objXmlDocument1.GetElementsByTagName("Designation");
foreach (XmlNode n in nodes1) {
    if (n.Attributes["Role"].Value.Trim().Equals("XXX"){                                
        objnode1 = n;
        break;
    }
}
if (objnode1 != null){
    XmlNodeList innerNodes1 = objnode1.ChildNodes;
    XmlNode newNode1 = objXmlDocument1.CreateElement("Designation");
    XmlAttribute newAtt1 = objXmlDocument1.CreateAttribute("Role");
    newAtt1.Value = "Ka";
    newNode1.Attributes.Append(newAtt1);
    newNode1.InnerXml=objnode1.InnerXml;
    objXmlDocument1.DocumentElement.AppendChild(newNode1);
}
objXmlDocument1.Save(
    System.Web.HttpContext.Current.Server.MapPath("") + 
    "\\XMLSchema\\" + 
    "ABC.xml");