Getting a whole XML node with its markups in a string - c#

Given the following XML example
<aaa>
<bbb id="1">
<ccc att="123"/>
<ccc att="456"/>
<ccc att="789"/>
</bbb>
<bbb id="2">
<ccc att="321"/>
<ccc att="654"/>
<ccc att="987"/>
</bbb>
</aaa>
as an XmlDocument object called xDoc1, I managed to remove the first bbb node thanks to its ID and an XPath instruction, leaving the second bbb node alone in the aaa one.
But now I want to get this removed node and its markups in a single string, as the InnerText value of this node is equal to
<ccc att="123"/><ccc att="456"/><ccc att="789"/>
but I want my string to be equal to
<bbb id='1'><ccc att="123"/><ccc att="456"/><ccc att="789"/></bbb>
How can I do so ? Using XmlDocument is mandatory.
I tried to use the ParentNode method, but then it includes the other bbb node.
My C# code for the moment :
xDoc1 = new XmlDocument();
xDoc1.Load("file.xml"); // Containing the given example above.
XmlNodeList nodes = xDoc1.SelectSingleNodes("//bbb[#id='1']");
foreach (XmlNode n in nodes)
{
XmlNode parent = n.ParentNode;
parent.RemoveChild(n);
}
// At this point, xDoc1 does not contain the first bbb node (id='1') anymore.

Use OuterXml property of XmlNode
xDoc1 = new XmlDocument();
xDoc1.Load("file.xml"); // Containing the given example above.
XmlNodeList nodes = xDoc1.SelectSingleNodes("//bbb[#id='1']");
foreach (XmlNode n in nodes)
{
XmlNode parent = n.ParentNode;
parent.RemoveChild(n);
Console.WriteLine(n.OuterXml);
}

I would firstly suggest not using XmlDocument. It's old tech and has been superseded by XDocument, which gives you Linq2Xml and lots of explicit casting goodness when dealing with attributes etc.
Using the XDocument approach with Linq instead of XPath, it's quite a lot easier to work this problem:
var doc=XDocument.Load("file.xml");
var elToRemove = doc.Root.Elements("bbb").Single(el => (int)el.Attribute("id") == 1);
elToRemove.Remove();
Console.WriteLine(doc.ToString()); //no <bbb id="1">
Console.WriteLine(elToRemove.ToString()); //the full outer text of the removed <bbb>

Related

how to get specific nodes which has specific attribute in c#

I want to find the nodes which has a specific attribute (like in example below we have attribute attr )
<root>
<anynode id="1" attr="abc">
first node
</anynode>
<anynode id="2">
2nd node
</anynode>
<anynode id="3" attr="abc">
3rd node
</anynode>
<anynode id="4" attr="def">
4th node
</anynode>
</root>
and i want it to traverse with XMLDocument and XDocument both
and if i can get value of ID and ATTR in one ittration that would be great
i have googled little bit but i didnt find any path which can help me lead to
final result i want
1,abc , first node
3,abc , 3rd node
4,def , 4th node
any help will be appreciated
Using the System.Xml.Linq namespace we can take advantage of the XDocument class to find the "id" and "attr" attributes of the "anynode" element.
var xmlDocument = XDocument.Load(#"path to xml file");
var nodes = xmlDocument.Element("root")?.Elements("anynode");
if (nodes == null)
return;
foreach (var node in nodes)
{
var id = node.Attribute("id")?.Value;
var attr = node.Attribute("attr")?.Value;
Console.WriteLine($"ID = {id}, ATTR = {attr}");
}

Filter XMLNodeList using xPath & Wildcard characters

I have "XML" as below:
<ParentNode>
<ChildNode id="1" Display_Name="ABC"/>
<ChildNode id="2" Display_Name="DEF"/>
<ChildNode id="3" Display_Name="DAX"/>
<ChildNode id="4" Display_Name="LAM"/>
<ChildNode id="5" Display_Name="PKR"/>
<ChildNode id="6" Display_Name="UYA"/>
</ParentNode>
I want to get list of all the Nodes in XMLNodeList in C# using xPath having "A" [regardless of capitals or small] in Display_Name attribute.
What I've tried is:
root.SelectNodes("descendant-or-self::*[contains(#DISPLAY_NAME,'end')]")
Here, root is containing my XML and it is an object of XMLDocument.
Also, how can I make this filter by ignoring either Display_Name is in small letters or capital letters.
"I want to get list of all the Nodes in XMLNodeList in C# using xPath having "A" [regardless of capitals or small] in Display_Name attribute. "
Nature of XML and XPath is case-sensitive. There is no pretty way to do case-insensitive matching using XPath (at least in XPath 1.0, version that is supported by .NET). One known way is using translate() to convert Display_Name value to lower-case before doing further comparison, something like this (see related post) :
var xpath = #"//*[
contains(
translate(#Display_Name
,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
,'abcdefghijklmnopqrstuvwxyz'
)
,'a'
)
]";
var result = root.SelectNodes(xpath);
Try with below XPath
/ParentNode/ChildNode/#Display_Name
To get result for both
Above XPath will return you all results of ChildNode. Now iterate this XPath to extract all results
Hope it will help you :)
Use OuterXml method.
Try this:
//Load Data
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
//Go the xPath
XmlNode titleNode = xmlDoc.SelectSingleNode(xPath);
//Get the OutXml (You dont need to use a new variable)
string nodeValue = titleNode.OuterXml;
//Load this string as a new XmlDocument and use the second xPath
XmlDocument xmlDoc2 = new XmlDocument();
xmlDoc2.LoadXml(nodeValue);
titleNode = xmlDoc.SelectSingleNode(xPath2);

Looping through all nodes in xml file with c#

I have an xml document with setup similiar to this:
<invoice>
<IssueDate>2015-09-07</IssueDate>
<InvoiceType>380<InvoiceType>
<AccountingSupplierParty>
<Party>
<EndpointID></EndpointID>
<PartyName>
<Name>Company test</Name>
</PartyName>
</Party>
</AccountingSupplierParty>
</invoice>
This is just a little piece of the entire xml document, just to show how the file looks.
I would like to check all the elements too see if they have empty values, such as EndpointID in this example (I need to replace empty values with NA).
This is what I have so far:
public static void AddToEmptyElements()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("testXml.xml");
XmlNodeList nodes = xmlDoc.DocumentElement.ChildNodes;
foreach (XmlNode node in nodes)
{
Console.WriteLine(node.Name);
}
}
However, this code will only loop through the childs of the root node and not all the grandchilds (or great grandchilds) such as the <Party> and <EndpointID> elements. How can I include these elements in the loop?
I'm not in an environment to test code right now, but isn't it possible to write a recursive method to loop further down the nodes?
Something like this (untested code):
private static void handleNode(XmlNode node)
{
if(node.HasChildNodes)
{
foreach(XmlNode child in node.ChildNodes)
{
handleNode(child);
}
}
else
Console.WriteLine(node.Name);
}
then call this method in place of your Console.WrintLine()
As Jon Skeet already said, you could do this using LINQ to XML.
XDocument xml = XDocument.Load(path);
var emptyElements = xml.Descendants().Where(xe => String.IsNullOrEmpty(xe.Value));
foreach (var xe in emptyElements)
xe.Value = "NA";

inserting xml element into multiple nodes

I have the following XML
<ROOT>
<FSM338_Container>
<FSM338_Details>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<CASHBREAK>199</CASHBREAK>
<CASHLUNCH>199</CASHLUNCH>
</FSM338_Details>
<FSM338_Details>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<CASHBREAK>199</CASHBREAK>
<CASHLUNCH>199</CASHLUNCH>
</FSM338_Details>
</FSM338_Container>
<BillingReport>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<gaindacd>1</gaindacd>
<docnum>07000F</docnum>
</BillingReport>
<DataElements>
<unitid>12345</unitid>
<fbocost>0.00</fbo>
</DataElements>
</ROOT>
I need to load the xml doc and add in several elements whenever I find the element named "Uic" . In short if I find "Uic" add in the element <someElement>my stuff here</someElement> at the same level as UIC at all locations.
I'Ve used
XmlDocument xDoc = new XmlDocument();
xDoc.Load(#"path_to_xml.xml");
list = xDoc.GetElementsByTagName("Uic");
I used insertBefore to add in my element but I can get it to copy to only the first element
You can use SelectNodes() method of XmlNode which accepts xpath expression.
XmlNodeList nodes = xDoc.DocumentElement.SelectNodes("Uic");
foreach(XmlNode node in nodes) {
XmlElement element = xDoc.CreateElement("SomeElement");
element.InnerText = "anything";
node.ParentNode.AppendChild(element);
}

Xdocument, get each element(s) value

I have xml as follows:
<Reports>
<report>
<name>By Book</name>
<report_type>book</report_type>
<Object>Count Change</Object>
<Slicers detail="detail">
<Namespace>EOD</Namespace>
<BookNode>HighLevel</BookNode>
<DateFrom>T-2</DateFrom>
<DateTo>T-1</DateTo>
<System>NewSystem</System>
</Slicers>
</report>
</Reports>
I simply want to loop through the value of each element of the Xdocument (pref would be any element under Slicers) but to start with just all elements.
When I run the following:
var slicers = from c in config.Elements("Reports")
select c.Value ;
foreach (var xe in slicers)
{
Console.WriteLine(xe);
}
The output is a single line concatenating all the values together.
"By BookbookCount ChangeEODHighLevelT-2T-1NewSystem"
I want to loop through them one at a time, 'By Book' first, run some code then book etc etc.
I am sure this is simple, but cant get round it. I have tried foreach(Xelement in query) but same resulst
i would do it something like this;
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
//load in your xml here
XmlNodeList xnList = doc.SelectNodes("nodeYou'reLookingFor");
//for getting just the splicers you could do "Reports/report/Slicers"
foreach (XmlNode node in xnList)
string namespace = node["Namespace"].InnerText;
//go through all your nodes here
you're creating a xmldoc, loading your xml into it, creating a list which holds each node in the list (at a specified Xpath), and then looping through each. in the loop you can do whatever you want by referencing
node["nodenamehere"].InnerText

Categories