find xml node by inner text in xml document - c#

how can i retrieve node out of xml document by inner text.
for example
<w:t>WARNING</w:t>
node consists multiple times with different values in xml document.
I want to retrieve only those w:t nodes with inner text contains "WARNING" .
how can it be done?

To query elements with prefix you have to register proper prefix-to-namespace-URI mapping using XmlNamespaceManager, then use that registered prefix in your XPath, for example :
var xml = #"<root xmlns:w=""test"">
<w:t>WARNING</w:t>
</root>";
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
var nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
//register proper prefix-to-namespace-URI mapping
nsManager.AddNamespace("w", "test");
//following XPath used to select <w:t> nodes with inner text contains "WARNING"
var result = xmlDoc.DocumentElement.SelectSingleNode("//w:t[contains(., 'WARNING')]", nsManager);
//print result
Console.WriteLine(result.OuterXml);

Try this :
var wtNodes = elements.Where(e => e.Name.LocalName.Equals("w:t"));
var warningNodes = wtNodes.Where(node => node.Value.Contains("WARNING"));

Try this:
xmlNodeList xNlist= xDoc.selectNodes("//pre:t[.="WARNING"]",objXmlnsMgr);
Here:
xDoc is XmlDocument;
objXmlnsMgr is XmlNamespaceManager ('w' in your case) & pre is its prefix.

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

C# how to read single item in node xml

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.

Copy Node and change Value of an Attribute

I have the following XML File. I want to copy a new "Test" and change the ID of the Test. How is it possible?
I already can copy the nodes, unfortunately not on the correct position (see images) and I also canĀ“t change the ID.
Anyone have a solution for me?
Before:
After:
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(Before.xml");
XmlNode Set = xmldoc.DocumentElement;
string strXmlQuery = "/Toolings/Testing/Test1";
XmlNode NodeToCopy = Set.SelectSingleNode(strXmlQuery);
XmlNode NewNode = NodeToCopy.CloneNode(true);
NodeToCopy.AppendChild(NewNode);
Set.InsertAfter(NewNode, Set.LastChild);
XPathNavigator navigator = xmldoc.CreateNavigator();
navigator.MoveToRoot();
navigator.MoveToFirstChild();
navigator.MoveToFirstChild();
navigator.MoveToFirstChild();
navigator.MoveToFirstChild();
navigator.SetValue("5678");
xmldoc.Save(After.xml");
Here is an example using System.Xml.Linq.XDocument which is a much easier API than XmlDocument:
//You can also use Load(), this is just so I didn't have to make a file
XDocument doc = XDocument.Parse("<Toolings><Testing><Test><ID>1234</ID></Test></Testing></Toolings>");
//Grab the first Test node (change the predicate if you have other search criteria)
var elTest = doc.Descendants().First(d => d.Name == "Test");
//Copy the node, only necessary if you don't know the structure at design time
XElement el = new XElement(elTest);
el.Element("ID").Value = "5678";
//inject new node
elTest.AddAfterSelf(el);
doc.Save("After.xml");

Delete a whole Node from an Xml Advertisement file?

I am trying to delete a whole XmlNode which matches a certain condition
The format of my xml file is as follows:
<?xml version="1.0" encoding="utf-8"?>
<Advertisements>
<Ad>
<ImageUrl>image/Hydrangeas.jpg</ImageUrl>
<NavigateUrl>www.google.com</NavigateUrl>
<AlternateText>nbfndbf</AlternateText>
<ID>0</ID>
<Impressions>1</Impressions>
</Ad>
</Advertisements>
My deleting code:
XElement x =
new XElement("Ad",
new XElement("ImageUrl", lblImageURL.Text),
new XElement("NavigateUrl", lblImageURL.Text),
new XElement("AlternateText", lblAlternateText.Text),
new XElement("ID", lblID.Text),
new XElement("Impressions", lblfrequency.Text));
string filepath = Request.PhysicalApplicationPath.ToString() + "Adrotator.xml";
XmlDocument xD = new XmlDocument();
xD.LoadXml(x.ToString());
XmlNode xN = xD.FirstChild;
xN.ParentNode.RemoveChild(xN);
**xD.Save(filepath);**
I am getting an error Invalid XML document. The document does not have a root element.
You can use linq to xml to achieve this here exmple how to remove node where value ID = 0
var q = (from c in doc.Descendants("Advertisements")
from v in c.Elements("Ad")
where (int) v.Element("ID") == 0
select v).Remove();
here is another example using xpath
doc.XPathSelectElement("Advertisements/Ad[ID = 0]").Remove();
You create a new XDocument (doc) with the following code:
XDocument doc = XDocument.Load(filepath);
Is there something in the Xml file (with a root element)? Also, you don't seem to use doc in the code, so it's at least not required.

Select an XML node via XPath at an arbitrary depth

Having an XML document, I want to get the first node with a certain name, no matter in which nesting depth it is contained.
I tried several things without success:
var node1 = doc.SelectSingleNode(#"//Shortcut");
var node2 = doc.SelectSingleNode(#"/*/Shortcut");
var node3 = doc.SelectSingleNode(#"//*/Shortcut");
var node4 = doc.SelectSingleNode(#"*/Shortcut");
...
Each call results in a NULL node.
I think it should be some trivial XPath syntax. Can you help me?
(In case this matters: The XML document is an input file for a WiX project, so there could be some namespace issues involved?!?).
Edit
I also tried the following:
var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, #"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(#"ns", #"http://schemas.microsoft.com/wix/2006/wi");
together with:
var node1 = doc.SelectSingleNode(#"//Shortcut", nsm);
var node2 = doc.SelectSingleNode(#"/*/Shortcut", nsm);
var node3 = doc.SelectSingleNode(#"//*/Shortcut", nsm);
var node4 = doc.SelectSingleNode(#"*/Shortcut", nsm);
...
Leading to the same results.
Edit 2 - Solution
I found the solution:
var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, #"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(#"ns", #"http://schemas.microsoft.com/wix/2006/wi");
and then
var node1 = doc.SelectSingleNode(#"//ns:Shortcut", nsm);
This succeeded.
The XPath expression that selects exactly the wanted node (and nothing in addition) is:
(//x:Shortcut)[1]
So, using:
doc.SelectNodes("(//x:Shortcut)[1]", someNamespaceManager)
where
the prefix "x" is bound to the namespace "http://schemas.microsoft.com/wix/2006/wi"
in someNamespaceManager
This has an advantage over the proposed solution (to use SelectSingleNode()), because it can easily be adjusted to select the N-th wanted node in the XML document.
For example:
(//x:Shortcut)[3]
selects the 3rd (in document order) x:Shortcut element, and
(//x:Shortcut)[last()]
selects the last (in document order) x:Shortcut element in the XML document.
Why do not use XDocument?
XDocument doc = XDocument.Load("test.xml");
doc.Descendants("Shortcut").First();
IMO XDocument is faster and more readable than XPath.
I finally found the solution by myself:
var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, #"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(#"ns", #"http://schemas.microsoft.com/wix/2006/wi");
and then
var node1 = doc.SelectSingleNode(#"//ns:Shortcut", nsm);
This succeeded.

Categories