I need to take in XML with common parent nodes but with varying child nodes. Once I get it, I need to grab the tag names of the child nodes and use those names as headers. In the following example, all incoming XML will be wrapped as follows:
<customers>
<customer>
...varying child nodes that do not have child nodes themselves
</customer>
</customers>
I have found that this works:
List<string> headerList = new List<string>();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(someXML);
XmlNodeList xnl = xmlDoc.SelectNodes("customers/customer");
foreach (XmlNode xn in xnl)
{
for (int x = 0; x < xn.ChildNodes.Count; x++)
{
headerList.Add(xn.ChildNodes[x].Name.ToString());
}
}
Is there a better way to do this?
Thanks in advance.
This should do the trick;
XDocument doc = XDocument.Load(someXML);
var headerList = doc.Descendants("customer").Elements().Select(x => x.Name);
Not necessarily "better", but it's a bit more concise I guess.
Related
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
I have xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><SENT_110 xmlns:ns2="http://www.mf.gov.pl/SENT/2017/01/18/STypes.xsd" xmlns="http://www.mf.gov.pl/SENT/2017/01/18/SENT_110.xsd"><SentNumber>SENT20180416000032</SentNumber><KeyNumber><ns2:SenderKey>KS-28YM</ns2:SenderKey><ns2:RecipientKey>KR-52DH</ns2:RecipientKey><ns2:CarrierKey>KD-48WW</ns2:CarrierKey></KeyNumber>
I want to read in separate SenderKey, RecipientKey & CarrierKey.
When i use this code:
XmlTextReader reader = new XmlTextReader(file);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("ns", xmlDoc.DocumentElement.NamespaceURI);
XmlNodeList nodeList = xmlDoc.SelectNodes("/ns:SENT_110/ns:KeyNumber", nsmgr);
foreach (XmlNode node in nodeList)
{
key = node.InnerText;
MessageBox.Show(key);
}
i've got something like this: KS-28YMKR-52DHKD-48WW, without any separate between key.
How i could read only one key?
Use the following XPath:
"/ns:SENT_110/ns:KeyNumber/*"
It will return all nested nodes to you.
If the structure of the XML is fixed it is rather easy by using XDocument:
var xmlText = "<SENT_110 xmlns:ns2=\"http://www.mf.gov.pl/SENT/2017/01/18/STypes.xsd\" xmlns=\"http://www.mf.gov.pl/SENT/2017/01/18/SENT_110.xsd\"><SentNumber>SENT20180416000032</SentNumber><KeyNumber><ns2:SenderKey>KS-28YM</ns2:SenderKey><ns2:RecipientKey>KR-52DH</ns2:RecipientKey><ns2:CarrierKey>KD-48WW</ns2:CarrierKey></KeyNumber></SENT_110>";
var xml = XDocument.Parse(xmlText);
var nodes = xml.Descendants();
var senderKey = nodes.First(d => d.Name.ToString().EndsWith("SenderKey")).Value;
var recipientKey = nodes.First(d => d.Name.ToString().EndsWith("RecipientKey")).Value;
var carrierKey = nodes.First(d => d.Name.ToString().EndsWith("CarrierKey")).Value;
See HERE for a working snippet. If this is just a part of a bigger XML or the structure can be different maybe some more complex searching is needed.
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.
Iam trying to get a particular node with value equals my input parameter,my xpath is like this where b is the node I need
string xpath = "/Batches/Measurement/Batch[market=someval]/b";
<?xml version="1.0" encoding="utf-8" ?>
<Batches>
<Measurement>
<Batch>
<market>someval</market>
<b>someval</b>
</Batch>
</Measurement>
</Batches>
var xmlNode = xmlDoc.SelectNodes(xpath);
no nodes retruned always count 0 ,I checked that the xmldoc is loaded properly.
Your xpath is nearly perfect. Only keep in mind const values have to be put in apostrophe:
"/Batches/Measurement/Batch[market='someval']/b"
Update: C# code example:
XmlNodeList nodeList;
nodeList = root.SelectNodes("/Batches/Measurement/Batch[market='someval']/b");
foreach (XmlNode node in nodeList)
{
for (int i = 0; i < node.ChildNodes.Count; i++)
{
Console.WriteLine(node.ChildNodes[i].InnerText);
}
}
The return value of SelectNodes is a nodeList. You have to iterate through it.
And a little bit shorter:
XmlElement root = doc.DocumentElement;
string text;
text = root.SelectSingleNode("/Batches/Measurement/Batch[market='someval']/b").InnerText;
Console.WriteLine(text);
Have you thought about using LINQ to XML?
It is slightly more efficient and shorter clearner syntax for selecting. I know you asked about Xpath so feel free to ignore this. Just making you aware of the option
var doc = XDocument.Load("c:\\tmp\\test.xml");
var result = doc.Descendants().Where(x => x.Element("b") != null)
.Select(x => x.Element("b").Value);
I load an XmlDocument and then select some nodes into an XmlNodeList instance. If I edit any of those nodes, the XmlDocument will be modified
XmlDocument xd = loadXml();
XmlNodeList xnl = xd.SelectNodes("/root/nodes");
foreach (XmlNode n in xnl)
{
n.InnerText = "";
}
So I understand that modifying the XmlNodeList - modifies the XmlDocument that the node list was taken from.
Is there some way to create a deep copy (I think that's what I need) of the list of nodes into another XmlElement, so that when I modify these nodes they will be independent of the original location where they were copied from?
There is more than one way to skin an xml cat. This is just one.
var xd = new XmlDocument();
xd.LoadXml("<root><nodes><node>1</node><node>2</node></nodes></root>");
var xnl = xd.SelectSingleNode("/root/nodes").Clone();
foreach (XmlNode n in xnl)
{
n.InnerText = "x";
}
Console.Out.WriteLine(xd.OuterXml);
Console.Out.WriteLine("--------------");
Console.Out.WriteLine(xnl.OuterXml);
You would need to create your own copies using .CloneNode. MSDN has an example.