Problems accessing certain node reading xml with C# - 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");

Related

Extracting objects from xml that uses node prefixes using xpath

I have the following XML in a file called C:\temp\config.xml:
<?xml version="1.0" encoding="utf-8"?>
<dvp:systemConfig xmlns:devop="urn:foo.com:sys:rules">
<dvp:map id="rootFolderMap">
<dvp:entry key="anything" value="folder1"/>
<dvp:entry key="config" value="folder2"/>
<dvp:defaultValue value="folder1" />
</dvp:map>
<dvp:map id="folderMappings">
<dvp:entry key="SYS" value="System" />
<dvp:entry key="OPS" value="Operations" />
<dvp:entry key="DEV" value="Development" />
<dvp:defaultValue value="Miscellaneous" />
</dvp:map>
</dvp:systemConfig>
I am now trying to write C# code that will extract values from this XML. In particular, the list of value properties in the nodes.
List<string> folderNames = new List<string>
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\temp\config.xml");
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
XmlNodeList xmlNodeList =
doc.SelectNodes("/systemConfig/map[#id='folderMappings']/entry",nsMgr);
foreach (XmlNode xmlNode in xmlNodeList)
{
// I'm hoping xmlNodeList now contains a list of <dvp:entry> nodes.
string folderName = xmlNode.Attributes["value"].ToString().Trim();
folderNames.Add(folderName);
}
However, this code returns an empty xmlNodeList, so the final loop has no items.
I'm not sure how to use the XmlNamespaceManager to pick up the "dvp" prefix, or whether it figures this out when it loads the XmlDocument from the XML on disk.
Can anyone give me some guidance how one goes about using xpath to retrieve values for xml with prefixed nodes? Unfortunately I do not have the power to change the format of the XML so I have to work with the xml I'm provided with.
thanks heaps,
David.
you can ignore the namespace using local-name()
XmlNodeList xmlNodeList =
doc.SelectNodes("/*[local-name()='systemConfig']/*[local-name()='map'][#id='folderMappings']");

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.

Parsing XML for nodes, and then child nodes

My XML looks like this:
<data>
<location ....>
<stores>
<store ....></store>
<store ... ></store>
</stores>
</location>
</data>
I want to loop through all the location elements, and then loop through all the stores.
I also want access to the attributes of both location and store elements.
I have loaded the xml document:
var doc = new XmlDocument();
doc.LoadXml(myXmlAsString);
Let's say this is your sample XML
<data>
<location sample="something">
<stores>
<store atrb="1">store1</store>
<store atrb="2">store2</store>
</stores>
</location>
<location>
<stores>....</stores>
</location>
</data>
Then using XDocument of System.Xml.Linq, you access all the locations, stores and their attributes like this
var xmlString = File.ReadAllText(#"C:\YourDirectory\YourFile.xml");
XDocument geneva = XDocument.Parse(xmlString);
var locations = geneva.Descendants("location");
foreach (var location in locations)
{
var sampleAttribute = location.Attribute("sample").Value;
var stores = location.Descendants("store");
foreach (var store in stores)
{
var value = store.Value;
var atrbValue = store.Attribute("atrb").Value;
}
}
If you dont want to use XmlSerializer to get the typed data you can get nodes by criteria with SelectSingleNode or SelectNodes methods. This will give you ability to iterate through location elemets.
I would suggest creating classes to deserialize to because its easier to work with.
Loop through locations:
XmlNodeList xnList = doc.SelectNodes("/data/location");
foreach(XmlNode node in xnList)
{
//your code goes here..
}
Loop through all stores:
XmlNodeList xnList = doc.SelectNodes("/data/location/stores");
foreach(XmlNode node in xnList)
{
//your code here..
}

Why this XPath selects zero nodes?

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

XML and SelectNodes

A pretty newbie question as I rarely work with XML. I'm trying out writing stuff for the Subsonic API. The xml looks like this
<?xml version="1.0" encoding="UTF-8"?>
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.6.0">
<indexes lastModified="1313158157783">
<index name="A">
<artist name="Albums" id="5c5c3139322e3136382e322e31305c566f6c756d655f315c4d757369635c416c62756d73"/>
</index>
<index name="S">
<artist name="Singles" id="5c5c3139322e3136382e322e31305c566f6c756d655f315c4d757369635c53696e676c6573"/>
</index>
</indexes>
</subsonic-response>
I'm just trying to get the index nodes.
I'm trying this, but not sure if I am doing this right. Both the SelectNodes and SelectSingleNode are returning emtpy. I'm sure I am missing something simple.
XmlNamespaceManager nsmgr = new XmlNamespaceManager(index.NameTable);
nsmgr.AddNamespace("", "http://subsonic.org/restapi");
XmlNodeList xnList = index.SelectNodes("/subsonic-response/indexes/index", nsmgr);
XmlNode mainnode = index.SelectSingleNode("/subsonic-response", nsmgr);
foreach (XmlNode xn in xnList)
{
}
I've tried with and without the namespacemanager and it's the same thing
Try using a non-empty XML namespace prefix:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(index.NameTable);
nsmgr.AddNamespace("x", "http://subsonic.org/restapi");
XmlNodeList xnList = index.SelectNodes("/x:subsonic-response/x:indexes/x:index", nsmgr);
XmlNode mainnode = index.SelectSingleNode("/x:subsonic-response", nsmgr);
I've had trouble with trying to use the empty string as a (default) XML namespace prefix
How about:
nsmgr.AddNamespace("x", "http://subsonic.org/restapi");
And:
XmlNodeList xnList = index.SelectNodes("/x:subsonic-response/x:indexes/x:index", nsmgr);

Categories

Resources