Whats wrong with my XPath? - c#

I try to parse this XML file (config file from Chirpy):
<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="urn:ChirpyConfig"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:ChirpyConfig http://www.weirdlover.com/chirpy/chirp.xsd">
<FileGroup Name="Built.debug.js" Minify="false">
<File Path="jquery/jquery-1.7.2.js"/>
<File Path="jquery.address/jquery.address-1.4.js" />
</FileGroup>
</root>
with this code:
var path = Server.MapPath("~/Scripts/ScriptfilesMashup.chirp.config");
var file = new XPathDocument(path);
var nav = file.CreateNavigator();
var nodes = nav.Select("/root/FileGroup/File");
but nodes is always empty, regardless of how I call the nav.Select method. I barely used XPath before so maybe I'm doing it wrong - but what? Only the selector * gives me the root node.
What would be the selector to get the Path Attribute of all File nodes?
EDIT: SOLUTION
Thanks to Kirill, the final solution looks like this:
var path = Server.MapPath("~/Scripts/ScriptfilesMashup.chirp.config");
var file = new XPathDocument(path);
var nav = file.CreateNavigator();
var ns = "urn:ChirpyConfig";
XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable);
nsMgr.AddNamespace("x", ns);
var nodes = nav.Select("/x:root/x:FileGroup/x:File/#Path", nsMgr);
while(nodes.MoveNext())
{
var path = nodes.Current.Value;
}

It is because elements root, FileGroup and File are defined in urn:ChirpyConfig namespace.
Use this:
XPathDocument xmldoc = new XPathDocument(xmlFile);
XPathNavigator nav = xmldoc.CreateNavigator();
XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable);
nsMgr.AddNamespace("x", "urn:ChirpyConfig");
XPathNavigator result = nav.SelectSingleNode("/x:root/x:FileGroup/x:File", nsMgr);

Related

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.

Reading attribute of an XML file

I have this XML file, I can read all the the nodes
<?xml version="1.0" encoding="UTF-8"?>
<cteProc xmlns="http://www.portalfiscal.inf.br/cte" versao="1.04">
<CTe xmlns="http://www.portalfiscal.inf.br/cte">
<infCte versao="1.04" ID="CTe3512110414557000014604"></infCte>
</CTe>
</cteProc>
I have tried reading this using C#
string chavecte;
string CaminhoDoArquivo = #"C:\Separados\13512004-procCTe.xml";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(CaminhoDoArquivo); //Carregando o arquivo
chavecte = xmlDoc.SelectSingleNode("infCTe")
.Attributes.GetNamedItem("Id").ToString();
but something is wrong with this code.
If you want to use Linq To Xml
var xDoc = XDocument.Load(CaminhoDoArquivo);
XNamespace ns = "http://www.portalfiscal.inf.br/cte";
var chavecte = xDoc.Descendants(ns+"infCte").First().Attribute("id").Value;
PS: I am assuming your xml's invalid line is as
<infCte versao="1.04" id="CTe3512110414557000014604"></infCte>
replace
chavecte = xmlDoc.SelectSingleNode("infCTe").Attributes.GetNamedItem("Id").Value;
with
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("ab", "http://www.portalfiscal.inf.br/cte");
chavecte = xmlDoc.SelectSingleNode("//ab:infCte", nsmgr)
.Attributes.GetNamedItem("Id").Value;
I've also noticed that infCte doesn't have the ID attribute properly defined in your xml
Another possible solution is:
string CaminhoDoArquivo = #"C:\Separados\13512004-procCTe.xml";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(CaminhoDoArquivo); //Carregando o arquivo
// Select the node you're interested in
XmlNode node = xmlDoc.SelectSingleNode("/cteProc/CTe/infCte");
// Read the value of the attribute "ID" of that node
string chavecte = node.Attributes["ID"].Value;

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.

Adding an element to this xml structure

<root>
<element1>innertext</element1>
<element2>innertext</element2>
<element3>
<child1>innertext</child1>
</element3>
</root>
I have an xml structure shown above.
I would like to "append" the xml file (it is already created) to add another "child" inside element3>, so that it will look like this:
<root>
<element1>innertext</element1>
<element2>innertext</element2>
<element3>
<child1>innertext</child1>
<child2>innertext</child2>
</element3>
</root>
Linq to xml and/or Xpath would be great
EDIT:
I have tried doing this:
XElement doc = XElement.Load(mainDirectory);
XElement newElem = doc.Elements("element3").First();
newElem.Add(new XElement("child2", "child2innertext"));
doc.Add(newElem);
doc.Save(mainDirectory);
XmlDocument xDoc = new XmlDocument();
xDoc.Load("filename.xml");
foreach (XmlNode xNode in xDoc.SelectNodes("/root/element3"))
{
XmlElement newElement = xDoc.CreateElement("Child2");
xNode.AppendChild(newElement);
xNode.InnerText = "myInnerText";
}
With XDocument you can achieve this as:
string xml = "<root><element1>innertext</element1><element2>innertext</element2><element3><child1>innertext</child1></element3></root>";
var doc = XDocument.Parse(xml); //use XDocument.Load("filepath"); in case if your xml is in a file.
var el3 = doc.Descendants("element3").FirstOrDefault();
el3.Add(new XElement("child2", "innertext"));
Please, try this LINQPAD example
void Main()
{
var xml =
#"<root>
<element1>innertext</element1>
<element2>innertext</element2>
<element3>
<child1>innertext</child1>
</element3>
</root>";
var doc = XDocument.Parse(xml);
doc.Root.Element("element3")
.Add(new XElement("child2", "innertext"));
doc.Dump();
}

How to get element value using c#

XML file:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<content>
<FingerPrintUserDetails>
<UserID>e57645</UserID>
<UserName>Jill</UserName>
<FPData>AQAAABQAAAD0AAAAAQASAAEAWgAAAAAA8AAAAHfrWpB6BHZBL10voxpdxu2Km5XVNh*oUNC80Rvpql3RhlqOiBPeet6iRPwb/BdN1fCF4Y/WHbQ40*mqoUKqilgN7bUqNuXP7M299HUWtoAGEO3nDKXXAnHd7dgytZbmHVv*mRBPJDSRw9VY/R1yOIu2cCDlLM*F8Q1lvTfMFDdfwNZynI0e2ZauCF58f0UX56XLFBallaAauxP5mvvhUmcmc6ITg7RhH9wc4181kgPjCuZg38pQepE5U07XIa3hQP8fwxPzdprifXECgB1Z3pTXWQP0q4ZD0Inlbq6Gszo1ucPrhQA0jYQRXtJUVuyBeg</FPData>
<Address>Pune</Address>
<ContactNo>848488484884</ContactNo>
</FingerPrintUserDetails>
<FingerPrintUserDetails>
<UserID>444</UserID>
<UserName>John</UserName>
<FPData>AQAAABQAAADkAAAAAQASAAEAZAAAAAAA4AAAAPLnmQ8FymAAHWYutR5pdtYvfDVmjsqLeli8tOSTFAtw6AkfA0r8XwrMzp9jFZJI7DlBk4G94BMq55gPEG7uBLZUNYrvhv0jDlDFMOjWGJ9RoWekFveTC*oZ7Tq/xmxuvY6FzLHVo*xzdKQI73Y0f9/eeMC0OgqnbQ3I0IP6cTkkKnTUZJOXKr7IFPHkjJAvCDmU7ec4vG50JHdBJIObmbzVcO0huTUQyE7CR1qYkUjmNFKgVKWPLRupEk4l/Ek0BuAba*9JlhBVUHzZuKbDQLc9lTFwevAgDuuAwxfZaLS*</FPData>
<Address>nagpur</Address>
<ContactNo>464645763</ContactNo>
</FingerPrintUserDetails>
<FingerPrintUserDetails>
<UserID>5555</UserID>
<UserName>Jack</UserName>
<FPData>AQAAABQAAAAEAQAAAQASAAEAZAAAAAAA9AAAAPz5mQO3uTeXLfU5Mb74XbCX5rERGZFPQMVG1vPpX87306O5oURlYiIe5dasJ2S8NlBZu2UU3zaUpNnB7viYDB6*wfFlgtopn/WdbXW0Yhik3hj8nDreEmaK12To8qfAJx2ooq43i0wBIL*0Jkba*QpHIprSajrhnCg1PjOLMP37sEauJUwXJaoDR/PPQYIxTFE5kf8xzGlJmqiGejD*Y8R3ewU9yIrxkdQ0S//LCdacULt2QvS/I3APo/j0FAgSCOU3SBLdDL6UBPD4fLeEzo7uUIW8gUMThzZX*u2iUuNwJdqWC2NsFtWkUWt03sz3xYQpR8pLA4vrsUmldzUMWe8</FPData>
<Address>beed</Address>
<ContactNo>5745745747</ContactNo>
</FingerPrintUserDetails>
</content>
C#:
XmlDocument doc = new XmlDocument();
doc.Load("E://BioEnable_Project//fp_project_using_xml//fp_project_using_xml//Capture_Data.xml");
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("FPData");
foreach(XmlElement node in nodes)
{
MessageBox.Show(node.Value);
}
I have to check FPData value on each node..i use above code but not getting..
In your XPath, provide the full path to the node.
XmlNodeList nodes = root.SelectNodes("/content/FingerPrintUserDetails/FPData");
What is happening is that there is no direct FPData node under the document root.
XmlNodeList nodes = root.SelectNodes("content/FingerPrintUserDetails");
it will return array of FingerPrintUserDetails, then find FPData in them
XmlNodeList res = nodes[index].SelectNodes("FPData");
Using LINQ to XML:
XDocument doc = XDocument.Load("XmlFilePath");
var selectors = from elements in doc.Elements("content").Elements("FingerPrintUserDetails")
select elements;
foreach (var element in selectors)
{
MessageBox.Show(element.Element("FPData").Value);
}
XmlDocument doc = new XmlDocument();
doc.Load("E://BioEnable_Project//fp_project_using_xml//fp_project_using_xml//Capture_Data.xml");
XmlNodeList lst = doc.GetElementsByTagName("FingerPrintUserDetails");
foreach (XmlElement elem in lst)
{
XmlNode pfData = doc.GetElementsByTagName("FPData")[0];
MessageBox.Show(pfData.Value);
}

Categories