I want to remove some child elements from an XML structure using RemoveChild() if a node is empty. My XML:
<Customers>
<customer>
<Name>John</Name>
<Age>25</Age>
<Status></Status>
</Customer>
<customer>
<Name>John</Name>
<Age></Age>
<Status></Status>
</Customer>
</Customers>
Should become:
<Customers>
<customer>
<Name>John</Name>
<Age>25</Age>
</Customer>
<customer>
<Name>John</Name>
</Customer>
</Customers>
My code so far:
XmlElement element3 = xmlDocument.CreateElement("Age");
element3.InnerText = str3;
element1.AppendChild((XmlNode)element3);
XmlElement element4 = xmlDocument.CreateElement("Status");
element4.InnerText = str4;
element1.AppendChild((XmlNode)element4);
How can I remove the empty node resp. nodes if there is more than one empty node?
Add a condition to only create the element if you need to:
if (!string.IsNullOrEmpty(status))
{
XmlElement statusElement = xmlDocument.CreateElement("Status");
statusElement.InnerText = status;
customerElement.AppendChild((XmlNode)statusElement);
}
Or if you need to remove it after it's already created (e.g. because you get XML from an external source with an empty Status), use the same sort of condition to remove it:
if (!string.IsNullOrEmpty(status))
{
customerElement.RemoveChild(statusElement);
}
That is because you are trying to remove a child element that simply does not exist. You must understand that in this context, the RemoveChild() method expects a reference to an existing node within the parent's children.
If i were to use your code sample above and create a standalone representation of this, it would look like this:
XmlDocument doc = new XmlDocument();
XmlElement element1 = doc.CreateElement("Customer");
XmlElement element2 = doc.CreateElement("Name");
element2.InnerText = "John";
element1.AppendChild(element2);
XmlElement element3 = doc.CreateElement("Age");
element3.InnerText = "25";
element1.AppendChild(element3);
XmlElement element4 = doc.CreateElement("Status");
element4.InnerText="";
element1.AppendChild(element4);
doc.AppendChild(element1);
element1.RemoveChild(element1.SelectSingleNode("Status"));
Using Linq-to-XML:
If you want nodes like:
<a>
<b>
<c></c>
</b>
</a>
to become:
<a />
Use:
XElement root = XElement.Load(file);
root.Descendants().Reverse().ToList().ForEach(x =>
{
if (x.IsEmpty)
x.Remove();
});
But if you want it to be:
<a>
<b />
</a>
Remove the .Reverse()
Related
In XML Document:
Foo.xml
<products>
<product>
<id>1</id>
<name>Foo</name>
</product>
<product>
<id>2</id>
<name>Bar</name>
</product>
</products>
How to get this root element, iterate over his child elements and get their properties?
Bar.cs
XmlDocument doc = new XmlDocument();
doc.Load(path + "/foo.xml");
XmlNode mainNode = doc.DocumentElement.SelectSingleNode("products");
XmlNode root = mainNode.FirstChild; //null
foreach (XmlNode node in mainNode)
{
int id = Convert.ToInt32(node["id"].InnerText);
string name = node["name"].InnerText);
list.Items.Add(id);
list.Items.Add(name);
}
This code implicates that mainNode is null. What is the best practise of doing that?
The DocumentElement is the outermost element of the XML, i.e. the <products> element. You can't select another <products> element below it.
What you can do:
XmlNode mainNode = doc.SelectSingleNode("products");
or
XmlNode mainNode = doc.DocumentElement;
or
XmlNode mainNode = doc.DocumentElement.SelectSingleNode("//products");
The second one is probably the fastest, since it does not need to parse and process a query. The last one is overkill and should be avoided for clean code reasons (KISS principle).
I want get <SNILS> node:
<ArrayOfEmployee xmlns=""
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" version="2.0.11"
formatVersion="2.0" system="ARM">
<Employee>
<AdditionalLaborAgreement i:nil="true" /> <CertificateEducationList>
<Document> <SNILS>1111111111111</SNILS>
</Document>
</CertificateEducationList>
</Employee>
Code:
XmlNodeList nodes = xml.GetElementsByTagName("Employee");
XmlNode node = xml.SelectSingleNode("SVED_PR_GS/ZGLV/FILENAME");
int Count = 2;
foreach (XmlNode n in nodes)
{
XmlNode smr_vsi = n.SelectSingleNode("SNILS");
Console.WriteLine(n.SelectSingleNode(smr_vsi.InnerText));
}
Error: Console.WriteLine(n.SelectSingleNode(smr_vsi.InnerText));
The object reference does not point to an instance of the object.
Your XML is malformed. Its missing </ArrayOfEmployee> element.
You can get the desired node in one of the 2 ways:
// Provide full XPath
XmlNode smr_vsi = n.SelectSingleNode("CertificateEducationList/Document/SNILS");
//Provide find on any path hint.
XmlNode smr_vsi = n.SelectSingleNode("//SNILS");
But, do check for null before using it:
if(smr_vsi != null)
Console.WriteLine(smr_vsi.InnerText);
First I want to find and select the PID"5678" from the <Tool>. With help of this PID, i want to find and select the ID"5678" from the <Parent>. The PID and the ID are the same value, but I have to find it from the <Tool> first.
At the moment I have following Code, to select the first PID. How can I "copy" this value and search with them the Attribute "ID"?
List<string> urls = xmldoc2.Descendants("PID").Select(x => x.Attribute("5678").Value).ToList();
<Tools>
<Tools>
<Tool>
<ID>1234</ID>
<PID>5678</PID>
<Name>Test</Name>
</Tool>
</Tools>
<Type>
<Parent>
<ID>5678</ID>
<PID>9999</PID>
<Name>Test2</Name>
</Parent>
</Type>
</Tools>
Notice that your Xml has multiple Root nodes - which does not work well.
So wrap it into single parent node (i.e. "Root" in below example)
Something of this sort should help you.
string xmlData = #"... Your Xml here....";
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlData);
var pidNodes = xmlDoc.SelectNodes("//Root/Tools/Tools/Tool/PID");
foreach(XmlNode node in pidNodes)
{
var typeNodeForPid = xmlDoc.SelectSingleNode(string.Format("//Root/Type/Parent[ID = '{0}']", node.InnerText));
}
I am trying to add an XML node to multiple parent nodes(which have same name). But it is only adding to the Last node of the XML and not in all.
input XML
<Record>
<Emp>
<ID>12</ID>
<Name>ABC</Name>
</Emp>
<Emp>
<ID>12</ID>
<Name>ABC</Name>
</Emp>
</Record>
I want to add the Location element to every Emp node. My code is as below:
XmlNodeList xNodeList = doc.SelectNodes("/Record/Emp");
XmlElement xNewChild = doc.CreateElement("Location");
xNewChild.InnerText = "USA";
foreach (XmlNode item in xNodeList)
{
item.AppendChild(xNewChild);
}
doc.Save(path);
but I am getting output like this:
<Record>
<Emp>
<ID>12</ID>
<Name>ABC</Name>
</Emp>
<Emp>
<ID>12</ID>
<Name>ABC</Name>
<Location>USA</Location>
</Emp>
</Record>
The Location element has not been added to the first Emp node.
Note: After debugging, I am able to find that the element has been added even for the first Emp node. But, in the saved XML file I am seeing this strange behavior.
Your xNewChild is a single new element. Simply adding it to multiple nodes will only serialize to the last node. A change like this should work:
XmlNodeList xNodeList = doc.SelectNodes("/Record/Emp");
foreach (XmlNode item in xNodeList)
{
XmlElement xNewChild = doc.CreateElement("Location");
xNewChild.InnerText = "USA";
item.AppendChild(xNewChild);
}
doc.Save(path);
I'm navigating XML document with XPathNodeIterator, and I want to change some nodes' values.
I can't figure out how :(
Here's the code I'm using:
XPathDocument docNav = new XPathDocument(path);
XPathNavigator nav = docNav.CreateNavigator();
nav.MoveToRoot();
XPathNodeIterator itemsIterator = nav.Select("/foo/bar/item");
while (mediumsIterator.MoveNext())
{
XPathNodeIterator subitemsIterator = itemsIterator.Current.Select("SubitemsList/name");
while (subitemsIterator.MoveNext())
{
XPathNodeIterator nodesIterator = itemsIterator.Current.Select("Param");
nodesIterator.MoveNext();
String the_params = nodesIterator.Current.Value;
// check if I need to modify nodesIterator.Current.Value
// ...
// ok I do - how?
}
}
And the XML file sample:
<?xml version="1.0" encoding="utf-8"?>
<foo>
<bar>
<item>
<Param />
<SubitemsList>
<name>name one</name>
<name>name two</name>
...
</SubitemsList>
</item>
...
</bar>
</foo>
Or maybe there's a better way to do this?
I found a way:
Replace XPathDocument with XmlDocument
When I get to the needed node
...
XmlNode node = ((IHasXmlNode)nodesIterator.Current).GetNode();
node.InnerText = "new text";