Why this XPath selects zero nodes? - c#

I have this XML:
<?xml version="1.0" encoding="utf-8"?>
<!-- Report generated by xxx -->
<report AppKey="stuffs" AppId="123">
<physician name="AAA BBB">
....
<services>
<service id="1" diagnostic="345" />
<service id="2" diagnostic="253" />
<service id="3" diagnostic="585" />
....
</services>
</physician>
</report>
and this c# code
XmlDocument doc = new XmlDocument();
doc.Load(file);
XmlNodeList xnList = doc.SelectNodes("/report/physician/services/*");
My problem is that the xnList is always empty, I tried with "/report/*" which return 0, tried with "/report/physician/*" which returns the same, only "*" returns the entire xml file. What I want to do is to select every <service> and then get their attributes. I cant seem to find a way to get every service element, because my queries always return nothing.

Can you use LINQtoXML? In that case it should be as simple as:
var doc = XDocument.Load(file);
XNamespace ns = "http://www.cnas.ro/siui/2.0";
var nodes = doc.Root.Element(ns + "physician")
.Element(ns + "services")
.Elements(ns + "service");
You can also use Descendants which will take the matching nodes regardless of their position in the tree, like this:
var nodes = doc.Root.Descendants(ns + "service");
Either way, you will get an IEnumerable<XElement> that you can easily map.
N.B. remember to add using System.Xml.Linq; in your directives.
UPDATE:
For mapping to the attributes, it is a matter of opinions... I would go like this:
var services = from n in nodes
select new
{
Id = n.Attribute("id").Value,
Diagnostic = n.Attribute("diagnostic").Value
};
services will be an IEnumerable<AnonymousType> which you can then iterate on:
foreach (var service in services)
{
Console.WriteLine(service.Id + " - " + service.Diagnostic);
}

Remove the asterisk;
XmlNodeList xnList = doc.SelectNodes("/report/physician/services/service");
foreach (XmlNode service in xnList)
x = service.Attributes["id"].Value;

This should select all service elements, no matter where they are in the file:
XmlNodeList xnList = doc.SelectNodes("//service");
Click here to find more XPath expressions

The below XPath should work for you.
XmlNodeList xnList = doc.SelectNodes("/report/physician/services/service");

Related

Get a list of ID Attributes from an XML File C#

I am trying to get a list of the Service IDs from the xml file below.
<Settings>
<SomeTag>Some inner text</SomeTag>
<Services ID="Downtown Location">
<Service ID="22923">Basic</Service>
<Service ID="22926">Basic + 2</Service>
<Service ID="22927">Basic + 3</Service>
<Service ID="22928">Basic + 4</Service>
<Service ID="22929">Basic + 5</Service>
</Services>
<MoreTags>
<ATag></ATag>
<ATag></ATag>
<ATag></ATag>
<ATag></ATag>
</MoreTags>
</Settings>
I have tried several methods I found on line but each one has had some sort of problem. This was my last attempt.
List<string> ServiceList = new List<string>();
XmlDocument xdoc = new XmlDocument();
xdoc.Load(AppDomain.CurrentDomain.BaseDirectory + #"\Settings.xml");
XmlNodeList nodes = xdoc.DocumentElement.SelectNodes("/Services/Service");
foreach (XmlNode node in nodes)
{
ServiceList.Add(node.Attributes["ID"].Value);
}
return ServiceList;
In this case the nodes has no items. I have tried several variations of SelectNodes but still have no items. Earlier I tried XDocument and a LINQ query. I would prefer to do it that way, but I have yet to find an example that collects the IDs.
To be begin with, I believe it was a typo that you missed out the closing "Settings" Tag. To capture the ID using Linq to Xml, you could use.
XElement xmlNode = XElement.Load(filePath);
var result = xmlNode.Descendants("Service").Select(x=>x.Attribute("ID").Value);
Sample Output
Here is an example with System.Xml.Linq:
static void Main(string[] args)
{
var xmldoc = System.Xml.Linq.XDocument.Load(#"YOUR FILE");
foreach (var name in xmldoc.Descendants("Services").Elements()
.Select(x => new { Name = x.Name, Value = x.Value, ID=x.Attribute("ID")
}))
{
Console.WriteLine(name.ID.Value);
}
Console.ReadLine();
}
OUTPUT:
22923
22926
22927
22928
22929
The fix is to remove the leading / in the XPath expression in this line
XmlNodeList nodes = xdoc.DocumentElement.SelectNodes("/Services/Service");
to give you
XmlNodeList nodes = xdoc.DocumentElement.SelectNodes("Services/Service");
An XPath expression beginning with / starts the search for matching elements from the root of the document. You however have navigated to the document element and want to start the search from there.

Tricky to read XML from web service C#

I have looked everywhere, and cannot find anything to help me.
I am writing a program that connects to a webservice and then the webservice sends an XML response. After the response is received I have to retrieve certain values from it, but this is where it gets tricky
Here is a snippet of the returned XML:
<?xml version="1.0"?>
<MobilePortalSellingCategoriesHierarchy xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Response xmlns="http://blabla.com/service/">Successful</Response>
<ResponseNumber xmlns="http://blabla.com/service/">0</ResponseNumber>
<SellingCategoriesHierarchy xmlns="http://tym2sell.com/PortalService/">
<Response>Successful</Response>
<ResponseNumber>0</ResponseNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId xsi:nil="true" />
<SellingCategoryName>category1</SellingCategoryName>
<DeliveryMethod />
<DeliveryMethodNumber>0</DeliveryMethodNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId xsi:nil="true" />
<SellingCategoryName>category1_Item</SellingCategoryName>
<DeliveryMethod />
<DeliveryMethodNumber>0</DeliveryMethodNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId>2</SellingCategoryId>
<SellingCategoryName>Item2</SellingCategoryName>
<DeliveryMethod>Display</DeliveryMethod>
<DeliveryMethodNumber>1</DeliveryMethodNumber>
<VoucherValue>0.00</VoucherValue>
<IsVariablePrice>true</IsVariablePrice>
<MinimumVoucherValue>1.00</MinimumVoucherValue>
<MaximumVoucherValue>1000.00</MaximumVoucherValue>
<VoucherValueIncrement>1.00</VoucherValueIncrement>
<AdditionalInputItems>
<PortalAdditionalInputItem>
<InputItemId>-1</InputItemId>
<Label>Value:</Label>
<IsNumericOnly>true</IsNumericOnly>
<MaximumLength>7</MaximumLength>
<Hidden>false</Hidden>
</PortalAdditionalInputItem>
<PortalAdditionalInputItem>
<InputItemId>4</InputItemId>
<Label>Mobile Number</Label>
<IsNumericOnly>true</IsNumericOnly>
<MaximumLength>15</MaximumLength>
<Hidden>false</Hidden>
</PortalAdditionalInputItem>
</AdditionalInputItems>
<TwoStep>false</TwoStep>
<SelectedIcon>SamplePicture</SelectedIcon>
<UnSelectedIcon>SamplePicture</UnSelectedIcon>
This repeats from the SellingCategories node just under Response for a couple of times.
Here is a Snippet of my code where I get the XML as string.
XmlDocument xml = new XmlDocument();
xml.LoadXml(receivedData);
XmlNodeList xnList = xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
foreach (XmlNode xn in xnList)
{
string sellingCategoryName = xn["SellingCategoryName"].InnerText;
string SelectedIcon = xn["SelectedIcon"].InnerText;
string UnSelectedIcon = xn["UnSelectedIcon"].InnerText;
richTextBox1.AppendText(string.Format("Name: {0} {1} {2}", sellingCategoryName, SelectedIcon, UnSelectedIcon));
}
I have tried changing xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
to
xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy/SellingCategoriesHierarchy/SellingCategories/PortalSellingCategory");
I need to select each SellingCategoryName and list the SellingCategoryName(s) and all the other items underneath it.
I was hoping to get something in the lines of:
Category1
Category1_Item
Item2
SamplePicture
Sample Picture
Mine only reads the First Node and then returns "Successful" to me.
I havve also tried:
XElement root = XElement.Load("FilePath");
var sellingCategoryNames = from PortalSellingCategory in root.Elements("MobilePortalSellingCategoriesHierarchy")
where (string)PortalSellingCategory.Element("SellingCategoriesHierarchy").Element("SellingCategories").Element("PortalSellingCategory") != ""
select PortalSellingCategory;
foreach (var xEle in sellingCategoryNames)
{
richTextBox1.Text = (string)xEle;
}
Any help would be greatly appreciated.
What you are doing with
xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
is selecting your root node, which is just one. Thats why you only get one item in your list back. Is the hierarchy important? I can see that PortalSellingCategory can also be inside another PortalSellingCategory. If not maybe you could try the following select:
xml.SelectNodes("//PortalSellingCategory");
This will search for every node named "PortalSellingCategory" in your response, no mather where in the hierarchy it is.
EDIT:
And yes, you should look out for the namespaces, sry for didnt seeing that.
If you like geeting all the nodes with XPath you must create a new NamespaceManager and at it to your selectNodes call:
XmlDocument xml = new XmlDocument();
xml.LoadXml(data);
XmlNamespaceManager ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("ns", "http://tym2sell.com/PortalService/");
XmlNodeList xnList = xml.SelectNodes("//ns:PortalSellingCategory", ns);
I would use XElement instead of XMLDocument, and then use Linq to query or pick the elmements like: XElement xContact = ....
int contactno = (int?)xContact.Element("command").Element("contactperson").Attribute("contactpersonid") ?? -1;
if (xContact.Element("command").Element("contactperson").Element("name").Element("firstname") != null)
console.writeline(xContact.Element("command").Element("contactperson").Element("name").Element("firstname").Value);
var doc= new XmlDocument();
doc.Load("FilePath");
var nodeList = xml.GetElementsByTagName("PortalSellingCategory");
Hi,
It returns the collection of nodes, and you just have to query it to get needed informations.
Feel free to ask help if needed.
Dimitri.

Problems accessing certain node reading xml with C#

My XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<something.logger>
<add key="LoggerId" value="8a2ff9ef-d144-4dcb-86d8-6ccaf44def20">
</add>
<add key="FederationId" value="00000000-0000-0000-0000-000000000000" />
</something.logger>
</configuration>
My code:
XmlDocument xml = new XmlDocument();
xml.Load(Some-Valid-Path);
XmlNodeList xnList = xml.SelectNodes("/configuration/something.logger");
I am trying to get the Guid (or value..) of value.
In the end i want to get the string "8a2ff9ef-d144-4dcb-86d8-6ccaf44def20"
Thanks !
Use # at the beginning of attribute name to reference an attribute in XPath. Then you need to cast each item in list as XmlAttribute :
XmlNodeList xnList = doc.SelectNodes("/configuration/something.logger/add[#key='LoggerId']/#value");
foreach (XmlAttribute n in xnList)
{
Console.WriteLine(n.Value);
}
Use /# to access attributes:
XmlNodeList xnList = xml.SelectNodes("/configuration/something.logger/add/#value");

Selecting Particular Node List in XML

<Report xmlns="Microsoft.SystemCenter.DataWarehouse.Report.Alert" xmlns:p1="w3.org/2001/XMLSchema-instance"; Name="Microsoft.SystemCenter.DataWarehouse.Report.Alert" p1:schemaLocation="Microsoft.SystemCenter.DataWarehou?Schema=True">
<Title>Alert Report</Title>
<Created>6/27/2013 9:32 PM</Created>
<StartDate>6/1/2013 9:29 PM</StartDate>
<EndDate>6/27/2013 9:29 PM</EndDate>
<TimeZone>(UTC)</TimeZone>
<Severity>Warning, Critical</Severity>
<Priority>Low, Medium, High</Priority>
<AlertTable>
<Alerts>
<Alert>
<AlertName></AlertName>
<Priority></Priority>
</Alert>
</Alerts>
</AlertTable>
</Report>
So I'm trying to pull down the list of nodes that appear under Alerts child. So /Report/AlertTable/Alerts.
I've done very similar before but in this format it is not working for some reason. Can someone point me out in the right direction?
XmlDocument Log = new XmlDocument();
Log.Load("test.xml");
XmlNodeList myLog = Log.DocumentElement.SelectNodes("//Report/AlertTable/Alerts");
foreach (XmlNode alert in myLog)
{
Console.Write("HERE");
Console.WriteLine(alert.SelectNodes("AlertName").ToString());
Console.WriteLine(alert.SelectNodes("Priority").ToString());
Console.Read();
}
EDIT:
One of the responses had me try to use a bunch of namespace with p1 but had no such luck.
EDIT:
Did not work either:
var name = new XmlNamespaceManager(log.NameTable);
name.AddNamespace("Report", "http://www.w3.org/2001/XMLSchema-instance");
XmlNodeList xml = log.SelectNodes("//Report:Alerts", name);
From a site:
nodename Selects all nodes with the name "nodename"
/ Selects from the root node
// Selects nodes in the document from the current node that match the selection no matter where they are
So I believe
"/AlertTable/Alerts"
would work, as that would be 'from the root node' as well as
"Report/AlertTable/Alerts"
XPath Site
Figured this sucker out.
It had to do with the namespace of "Microsoft.SystemCenter.DataWarehouse.Report.Alert". Changing this to anything but that won't read the XML properly.
XmlDocument log = new XmlDocument();
log.Load(#"C:\Users\barranca\Desktop\test.xml");
// XmlNodeList xml = log.SelectNodes("//ns1:Alerts");
var name = new XmlNamespaceManager(log.NameTable);
name.AddNamespace("ns1", "Microsoft.SystemCenter.DataWarehouse.Report.Alert");
XmlNodeList xml = log.SelectNodes("//ns1:Alert", name);
foreach (XmlNode alert in xml)
{
Console.Write("HERE");
XmlNode test = alert.SelectSingleNode("//ns1:AlertName",name);
string testing = test.InnerText;
Console.Write(testing);
}

Get specific values from Xml

I don't how to extract the values from XML document, and am looking for some help as I'm new to C#
I am using XmlDocument and then XmlNodeList for fetching the particular XML document
Here is my code
XmlNodeList XMLList = doc.SelectNodes("/response/result/doc");
And my XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<result>
<doc>
<long name="LoadID">494</long>
<long name="EventID">5557</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
<doc>
<long name="LoadID">774</long>
<long name="EventID">5558</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
</result>
</response>
In this i have to fetch every the XMLData data that is under every doc tag and i have to fetch last doc tag EventID.
var xml = XDocument.Parse(xmlString);
var docs = xml.Root.Elements("doc");
var lastDocEventID = docs.Last()
.Elements("long")
.First(l => (string)l.Attribute("name") == "EventID")
.Value;
Console.WriteLine ("Last doc EventId: " +lastDocEventID);
foreach (var doc in docs)
{
Console.WriteLine (doc.Element("str").Element("TransactionDate").Value);
}
prints:
Last doc EventId: 5558
2014-05-28T14:17:31.2186777-06:00
2014-05-28T14:17:31.2186777-06:00
You can use two XPath expressions to select the nodes you want. To answer each part of your question in turn:
To select all of the XMLData nodes:
XmlNodeList XMLList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
To select the last EventId:
XmlNode lastEventIdNode =
doc.SelectSingleNode("/response/result/doc[position() =
last()]/long[#name='EventID']");
If not all doc nodes are guaranteed to have an event id child node, then you can simply:
XmlNodeList eventIdNodes =
doc.SelectNodes("/response/result/doc[long[#name='EventID']]");
XmlNode lastNode = eventIdNodes[eventIdNodes.Count - 1];
That should give you what you've asked for.
Update;
If you want the XML data inside each strXml element, you can use the InnerXml property:
XmlNodeList xmlList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
foreach(XmlNode xmlStrNode in xmlList)
{
string xmlInner = xmlStrNode.InnerXml;
}
There's one result tag short in your xml.
Try using this. It's cleaner too imho
XmlNodeList docs = doc.SelectSingleNode("response").SelectSingleNode("result").SelectNodes("doc");
Then you can use a combination of SelectSingleNode, InnerText, Value to get the data from each XmlNode in your list.
For example if you want the EventID from the first doc tag:
int eventID = int.Parse(docs[0].SelectSingleNode("long[#name='EventID']").InnerText);

Categories

Resources