Xdocument, get each element(s) value - c#

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

Related

C# How remove single xml parent element node without removing the contents inside the parent node

I am new to C#, kindly help me. How to remove the single xml element node 'PaymentRecord' and content inside that should not get deleted.
<Payments>
<PaymentRecord>
<PayId>2031</PayId>
<Reference>Policy03</Reference>
<StatusCode>ACV</StatusCode>
<MethodDetail>
<PaymentMethodDetail>
<CardPaymentDetails>
<CardHolderName>abcded</CardHolderName>
<CardTransactionDetails>
<StoredCard>N</StoredCard>
</CardTransactionDetails>
</CardPaymentDetails>
</PaymentMethodDetail>
</MethodDetail>
<CurrencyCode>USD</CurrencyCode>
</PaymentRecord>
</Payments>
I need to remove "PaymentRecord" element from the XML. I need like below
<Payments>
<PayId>2031</PayId>
<Reference>Policy03</Reference>
<StatusCode>ACV</StatusCode>
<MethodDetail>
<PaymentMethodDetail>
<CardPaymentDetails>
<CardHolderName>abcded</CardHolderName>
<CardTransactionDetails>
<StoredCard>N</StoredCard>
</CardTransactionDetails>
</CardPaymentDetails>
</PaymentMethodDetail>
</MethodDetail>
<CurrencyCode>USD</CurrencyCode>
</Payments>
I have tried my below code, but its deleting the complete node which I don't want to do :- here 'queuePayload' is the xml element
XmlNodeList payloadRecordList = queuePayload.SelectNodes("//Payments/PaymentRecord");
foreach (XmlElement singleNode in payloadRecordList)
{
XmlHelper.removeElem((XmlElement)singleNode.ParentNode, "//PaymentRecord");
XmlDocument xmlDoc = singleNode.OuterXml;
// my remaining logic goes based on "xmldoc" value - I will inserting this data to table
}
You can use System.Xml.Linq with its XDocument to achiev this. Load the input and create a new document out of it like:
XDocument inputDoc = XDocument.Load(inputFile, LoadOptions.None);
XDocument outputDoc = new XDocument();
var elements = inputDoc.Element("Payments").Elements().Select(pr => pr.Elements());
XElement newElement = new XElement("Payments");
foreach (var element in elements)
{
newElement.Add(element);
}
outputDoc.Add(newElement);
Console.WriteLine(outputDoc.ToString());
I think #Fructzwerg is slightly overcomplicating it.
You can remove the PaymentRecord node and add all its children to the root in one go.
var xDoc = XDocument.Load(filePath);
var paymentRecord = xDoc.Root.Element("PaymentRecord");
var nodes = xDoc.Root.Element("PaymentRecord").Elements();
paymentRecord.Remove();
xDoc.Root.Add(nodes);
Console.WriteLine(xDoc.ToString());
dotnetfiddle

How to get nodes from XML file without its attribute and put to a List of string

I would like to display the tag names of child nodes without its attributes. Then those tag names (nodes) should be put in a List of string. Here's example of my XML file:
<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
<CAR>
<ID>21</ID>
<MANUFACTURER>Ford</MANUFACTURER>
<MODEL>Fiesta</MODEL>
</CAR>
<CAR>
<ID>22</ID>
<MANUFACTURER>Peugeot</MANUFACTURER>
<MODEL>508</MODEL>
</CAR>
</ROOT>
So, the effect I want to get in a console output is shown below:
ID
MANUFACTURER
MODEL
Then I would like to store that ID, MANUFACTURER and MODEL tag names in a List of strings.
This is the code that I tried so far:
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = true;
try
{
xmlDocument.Load("XMLFile.xml");
}
catch (FileNotFoundException ex)
{
Console.WriteLine(ex);
}
Console.WriteLine(xmlDocument.OuterXml);
XmlNodeList nodeList = xmlDocument.SelectNodes("ROOT/CAR");
foreach(XmlNode node in nodeList)
{
Console.WriteLine(node.ChildNodes);
xmlNodes.Add(node.ChildNodes.ToString());
}
The problem is that it's not displaying the way I want to. As a result I only get two System.Xml.XmlChildNodes which seems to be corresponding to two <CAR> nodes, instead of its three child nodes, such as ID, MANUFACTURER and MODEL.
System.Xml.XmlChildNodes
System.Xml.XmlChildNodes
Adding items to a List basically adds the same thing as shown above.
What am I doing wrong?
If you have to use XmlDocument, then you can -
List<string> elements = new List<string>();
XmlNodeList CarNodes = xml.SelectNodes("Root/Car");
foreach(XmlNode c in CarNodes)
{
foreach(XmlNode n in c.ChildNodes)
{
if (!elements.Contains(n.Name))
{
elements.Add(n.Name);
}
}
}
But I find XDocument to be much simpler and better readability.
XDocument xdoc = XDocument.Parse(yourXmlString);
List<string> elements = xdoc.Descendants("Car")
.DescendantNodes().OfType<XElement>()
.Select(x => x.Name).Distinct().ToList();
And thats all you'll need. Easy to read as well, get all the descendants of "Car" Node and get all distinct names of XElements within it.
Another way to do it -
List<string> elements = xdoc.Descendants("Car").First()
.DescendantNodes().OfType<XElement>()
.Select(x => x.Name).ToList();
In this case I have removed the "distinct" and rather got just the first Car node ONLY. You can see the difference - if by any case some other Car node has an extra element, you'll miss getting that information by doing it this way.
You could loop through for children nodes:
1- You can define xmlNodes like a HashSet to avoid multiple tags like :
HashSet<string> xmlNodes = new HashSet<string>();
2 - Change little the code like :
....
XmlNodeList nodeList = xmlDocument.SelectNodes("ROOT/CAR");
foreach (XmlNode node in nodeList)
{
foreach(XmlNode element in node.ChildNodes)
{
if (element.NodeType == XmlNodeType.Element)
xmlNodes.Add(element.Name);
}
}
Demo
Console.WriteLine(string.Join(", ", xmlNodes));
Result
ID, MANUFACTURER, MODEL
I hope you find this helpful.

Reading XML nodes causing issues

I have one XML string, I am trying to read that using C#, but I am not getting child nodes. I am getting entire XML as inner XML string. I am not able to read the nodes. Here is my XML string and my code.
<Filters FilterName="706337_test">
<MemberName>Dorvil</MemberName>
<MemberId />
<ProviderName />
<ProviderId>706337</ProviderId>
<SelectedProjects>5030003</SelectedProjects>
<CNAChartSelected>false</CNAChartSelected>
<OldProject>false</OldProject>
</Filters>
C# code trying to read the XML nodes
XmlDocument xml = new XmlDocument();
xml.LoadXml(xmlstring);
XmlNodeList xnList = xml.SelectNodes("/Filters");
I can see only one child node that too filters, I need to read MemberId, MemberName etc., how to read them?
This is because your string in SelectNodes is wrong:
var xml = new XmlDocument();
xml.LoadXml(xmlstring);
var xnList1 = xml.SelectNodes("/Filters"); //list of 1 element
var xnList2 = xml.SelectNodes("/Filters/*"); //list of 7 elements
foreach (XmlNode node in xnList2)
{
Console.WriteLine(node.OuterXml);
}
Also you can use this:
var xElements = XElement.Parse(xmlstring).Elements();
foreach (var element in xElements)
{
Console.WriteLine(element);
}
You need to tell the app which nodes to read..
XmlDocument xml = new XmlDocument();
xml.LoadXml(xmlstring);
XmlNodeList xnList = xml.SelectNodes("/Filters");
foreach (XmlNode node in xnList)
{
string memberName = node["MemberName"].InnerText;
}
This lets the app know to read what is inside the MemberName node.. Do the same for the other nodes and post back your results. Debug as you go to see what you are getting out of each node.

Confused in getting nested elements and values via XmlDocument

I am trying to access quite a deep XML file, yet I get confused and just brute forced access to an element to get the elements within it, My problem is, it does not work (Object reference not set to an instance of an object) and my method of getting the "dictory" of the XML looks very inefficient,
My goal is to grab all the <ramStick> via a foreach loop since it can have 1-* ramSticks
Here is part of my C# code that I am having an issue with:
XmlDocument doc = new XmlDocument();
string xmlFilePath = #"C:\xampp\htdocs\userInfo.xml";
doc.Load(xmlFilePath);
XmlNodeList accountList = doc.GetElementsByTagName("account");
foreach (XmlNode node in accountList)
{
XmlElement accountElement = (XmlElement)node;
// I got inside this loop at this point and can get an accountElement with values
String hostname = accountElement.GetElementsByTagName("user")[0].InnerText;
// This is where I get confused and don't know what I am really doing and I just experiment
XmlNode accountRoot = accountElement.GetElementsByTagName("systemInfo")[0];
XmlElement ramNode = (XmlElement)accountRoot;
XmlNode ramInfo = ramNode.GetElementsByTagName("ramInfo")[0];
XmlElement ramList = (XmlElement)ramInfo;
XmlNodeList ramStick = ramList.GetElementsByTagName("ramStick");
// I want to run a foreach loop on each ramStick to get the values
foreach (XmlNode ramNodeForLoop in ramStick)
{
XmlElement ramData = (XmlElement)ramNodeForLoop;
String partNumber = ramData.GetElementsByTagName("partNumber")[0].InnerText;
}
}`
I have quite a big XML file which contains multiple <account> here is a sample of it:
<account>
<user>OYSTER-PC</user>
<systemInfo>
<dskInfo>
<dskInterface>
<deviceID>C:</deviceID><description>Local Fixed Disk</description><size>500000878592</size><freeSpace>377396776960</freeSpace><fileSystem>NTFS</fileSystem><volumeSerialNumber>4C922158</volumeSerialNumber>
</dskInterface>
<dskInterface>
<deviceID>D:</deviceID><description>CD-ROM Disc</description><size/><freeSpace/><fileSystem/><volumeSerialNumber/>
</dskInterface>
<dskInterface>
<deviceID>E:</deviceID><description>CD-ROM Disc</description><size/><freeSpace/><fileSystem/><volumeSerialNumber/>
</dskInterface>
</dskInfo>
<hddInfo>
<hddInterface>
<model>ST9500325AS ATA Device</model><interfaceType>IDE</interfaceType><name>\\.\PHYSICALDRIVE0</name><partitions>1</partitions><serialNumber>2020202020202020202020205636384547535146</serialNumber><status>OK</status>
</hddInterface>
</hddInfo>
<nicInfo>
<nicInterface>
<macAddress>48:5D:60:03:88:04</macAddress><description>Atheros AR9285 Wireless Network Adapter</description><ipAddress>192.168.1.10</ipAddress><ipSubnet>255.255.255.0</ipSubnet><defaultIpGateway>192.168.1.1</defaultIpGateway><dhcpServer>192.168.1.1</dhcpServer>
</nicInterface>
<nicInterface>
<macAddress>74:F0:6D:A8:4E:32</macAddress><description>Bluetooth Device (Personal Area Network)</description><ipAddress/><ipSubnet/><defaultIpGateway/><dhcpServer/></nicInterface>
<nicInterface>
<macAddress>20:41:53:59:4E:FF</macAddress><description>RAS Async Adapter</description><ipAddress/><ipSubnet/><defaultIpGateway/><dhcpServer/>
</nicInterface>
<nicInterface>
<macAddress>20:CF:30:55:0C:EF</macAddress><description>JMicron PCI Express Gigabit Ethernet Adapter</description><ipAddress/><ipSubnet/><defaultIpGateway/><dhcpServer/>
</nicInterface>
</nicInfo>
<ramInfo>
<ramStick>
<partNumber>M471B5273DH0-CK0 </partNumber><serialNumber>E2CE33AF</serialNumber><capacity>4294967296</capacity>
</ramStick>
<ramStick>
<partNumber>M471B5273DH0-CK0 </partNumber><serialNumber>630155D0</serialNumber><capacity>4294967296</capacity>
</ramStick>
</ramInfo>
</systemInfo>
</account>
You can use xpath like this:
foreach (XmlElement element in doc.SelectNodes("//account/systemInfo/ramInfo/ramStick"))
{
string partNumber = element["partNumber"].InnerText;
}
Note that since this call to SelectNodes returns only XmlElement, I can use XmlElement as type for the loop variable. Otherwise I'd have to use XmlNode.
After recoding so much,
Here is what I finally did...
XmlNode systemInfo = node.SelectSingleNode("systemInfo");
XmlNode ramInfo = systemInfo.SelectSingleNode("ramInfo");
XmlNodeList ramList = ramInfo.SelectNodes("ramStick");
foreach (XmlElement ramStick in ramList)
{
// add code here
}

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);
}

Categories