【发布时间】:2008-10-30 11:38:11
【问题描述】:
我有两个具有两个不同 XSD 架构和不同名称空间的 XML 文件。它们都具有相同的子结构。现在我需要将该节点(和所有子节点)从一个 XML 文档复制到另一个。
如果命名空间相同,克隆就可以了。有什么好的方法吗? (子结构稍后会改变 - 但会保持不变。)
【问题讨论】:
我有两个具有两个不同 XSD 架构和不同名称空间的 XML 文件。它们都具有相同的子结构。现在我需要将该节点(和所有子节点)从一个 XML 文档复制到另一个。
如果命名空间相同,克隆就可以了。有什么好的方法吗? (子结构稍后会改变 - 但会保持不变。)
【问题讨论】:
基本上,您需要一个 XSL 转换来创建名称相同但名称空间不同的新元素。
考虑以下输入 XML:
<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://tempuri.org/ns_old">
<child attrib="value">text</child>
</test>
现在您需要一个模板,上面写着“复制您看到的所有内容的结构和名称,但在您使用它时声明一个新的命名空间”:
<?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>
当您通过它运行上述 XML 时,会产生:
<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://tempuri.org/ns_new">
<child attrib="value">text</child>
</test>
您所有的http://tempuri.org/ns_old 元素都有效地更改了它们的命名空间。当您的输入 XML 同时具有多个命名空间时,XSL 很可能必须进行一些扩展。
【讨论】:
不确定这是否适用,但我在 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
【讨论】:
遵循 Tomalak 的示例(稍作修正),但使用 SetAttribute + OuterXml + InnerXml 更简单 常量字符串 xml_str = @"
";
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 );
}
【讨论】:
如果您希望在匹配某个属性时复制节点的所有子元素。您只需复制引用节点的InnerXML 并将其设置为等于新节点即可。
类似这样,下面,我有一个带有 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>
所以我只写以下代码:
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");
【讨论】: