Reputation: 645
I need to move a specific first child node and convert it into a parent node as follows:
I have changed the XML to make it clearer.
Original XML
<root version="1.0">
<body>
<nodeList projectName="testing charcharistics">
<node modelDescription="I'm parent node which needs to be removed">
<node modelCatalogNum="I'm First Son node to become parent node" attr1="1" attr2="2" ....... />
<node modelCatalogNum="NETDIR-1" />
<node modelCatalogNum="NETDIR-2" />
<node modelCatalogNum="NETDIR-3" />
.
.
.
.
</node>
</nodeList>
</body>
</root>
Output XML
<root version="1.0">
<body>
<nodeList projectName="testing charcharistics">
<node modelCatalogNum="I'm First Son node to become parent node" attr1="1" attr2="2" ....... />
<node modelCatalogNum="NETDIR-1" />
<node modelCatalogNum="NETDIR-2" />
<node modelCatalogNum="NETDIR-3" />
.
.
.
.
</node>
</nodeList>
</body>
</root>
As you can see the first child node has become a parent node.
I need a generic solution in C# code something with the following steps.
Can anyone help?
Upvotes: 0
Views: 959
Reputation: 101730
How about this generic approach:
private static void Invert(XmlNode startingNode, string path)
{
XmlNode node = startingNode.SelectSingleNode(path);
if (node != null)
{
XmlNode firstChild = node.SelectSingleNode("*");
if(firstChild != null)
{
XmlNodeList others =
node.SelectNodes("node()[not(self::*)] | *[position() > 1]");
foreach (XmlNode other in others)
{
firstChild.AppendChild(other);
}
node.ParentNode.ReplaceChild(firstChild, node);
}
}
}
You can call it like this:
Invert(doc, "/root/body/nodeList/node");
Alternatively, you could use an XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="nodeList/node">
<xsl:apply-templates select="*[1]" mode="newParent" />
</xsl:template>
<xsl:template match="*" mode="newParent">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="../node()[generate-id() !=
generate-id(current())]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 677
How about this?
XmlDocument doc = new XmlDocument();
doc.Load("Test.xml");
you could send in a variable to determine the node to remove XmlNodeList elementList = doc.GetElementsByTagName("node");
Just to Show the list
foreach (XmlNode node in elementList)
{
Console.Write(node.Name + " ");
foreach (XmlAttribute attr in node.Attributes)
{
Console.Write(attr.Name + ":" + attr.Value + " ");
}
Console.WriteLine();
}
Generic removal - basically remove attributes from parent and add the ones from first child, remove the child
var firstChild = elementList[0].FirstChild;
elementList[0].Attributes.RemoveAll();
for (int i = 0; i < firstChild.Attributes.Count; i++)
{
XmlAttribute item = doc.CreateAttribute(firstChild.Attributes[i].Name);
item.Value = firstChild.Attributes[i].Value;
elementList[0].Attributes.Append(item);
}
elementList[0].RemoveChild(firstChild);
Just to Show the list
Console.WriteLine();
foreach (XmlNode node in elementList)
{
Console.Write(node.Name + " ");
foreach (XmlAttribute attr in node.Attributes)
{
Console.Write(attr.Name + ":" + attr.Value + " ");
}
Console.WriteLine();
}
Console.ReadLine();
Upvotes: 0
Reputation: 1411
Here is the solution you can remove self closing tag separately.
Test.xml
- Your original xml and Test1.xml
- Modified xml
XmlDocument doc = new XmlDocument();
doc.Load(@"E:\Test.xml");
XmlNodeList elementList = doc.GetElementsByTagName("node");
for (int i = 0; i < elementList.Count; i++)
{
if (elementList[0].Attributes["modelDescription"].Value == "My Model Description")
{
elementList[0].Attributes["modelDescription"].Value = elementList[1].Attributes["modelDescription"].Value;
XmlAttribute newAttribute1 = doc.CreateAttribute("instanceName");
newAttribute1.Value = elementList[1].Attributes["instanceName"].Value;
elementList[0].Attributes.Append(newAttribute1);
XmlAttribute newAttribute2 = doc.CreateAttribute("modelCatalogNum");
newAttribute2.Value = elementList[1].Attributes["modelCatalogNum"].Value;
elementList[0].Attributes.Append(newAttribute2);
elementList[1].ParentNode.Attributes.Remove(elementList[0].Attributes["quantity"]);
elementList[0].FirstChild.RemoveAll();
}
}
doc.Save(@"E:\Test1.xml");
Upvotes: 2