XDocument get element that defines it's own namespace - c#

As question states. I have a xml document (below) and I need to get X_ScalarWebApi_DeviceInfo that defines namespace urn:schemas-sony-com:av. Unfortunately it results in an error: {System.NullReferenceException: Object reference not set to an instance of an object. I'm mainly interested in ServiceList element, but it doesn't work as well. Platform - Windows 10 mobile.
Any ideas?
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
<friendlyName>ILCE-6000</friendlyName>
<manufacturer>Sony Corporation</manufacturer>
<manufacturerURL>http://www.sony.net/</manufacturerURL>
<modelDescription>SonyDigitalMediaServer</modelDescription>
<modelName>SonyImagingDevice</modelName>
<UDN>uuid:000000001000-1010-8000-62F1894EE7BE</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-sony-com:service:ScalarWebAPI:1</serviceType>
<serviceId>urn:schemas-sony-com:serviceId:ScalarWebAPI</serviceId>
<SCPDURL/>
<controlURL/>
<eventSubURL/>
</service>
</serviceList>
<av:X_ScalarWebAPI_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
<av:X_ScalarWebAPI_Version>1.0</av:X_ScalarWebAPI_Version>
<av:X_ScalarWebAPI_ServiceList>
<av:X_ScalarWebAPI_Service>
<av:X_ScalarWebAPI_ServiceType>guide</av:X_ScalarWebAPI_ServiceType>
<av:X_ScalarWebAPI_ActionList_URL>http://192.168.122.1:8080/sony</av:X_ScalarWebAPI_ActionList_URL>
<av:X_ScalarWebAPI_AccessType/>
</av:X_ScalarWebAPI_Service>
<av:X_ScalarWebAPI_Service>
<av:X_ScalarWebAPI_ServiceType>accessControl</av:X_ScalarWebAPI_ServiceType>
<av:X_ScalarWebAPI_ActionList_URL>http://192.168.122.1:8080/sony</av:X_ScalarWebAPI_ActionList_URL>
<av:X_ScalarWebAPI_AccessType/>
</av:X_ScalarWebAPI_Service>
<av:X_ScalarWebAPI_Service>
<av:X_ScalarWebAPI_ServiceType>camera</av:X_ScalarWebAPI_ServiceType>
<av:X_ScalarWebAPI_ActionList_URL>http://192.168.122.1:8080/sony</av:X_ScalarWebAPI_ActionList_URL>
<av:X_ScalarWebAPI_AccessType/>
</av:X_ScalarWebAPI_Service>
</av:X_ScalarWebAPI_ServiceList>
</av:X_ScalarWebAPI_DeviceInfo>
</device>
</root>
Ah, the code:
XDocument xDoc = XDocument.Parse(xml_text);
//var av = xDoc.Root.GetDefaultNamespace();//.Attribute("xmlns");//
XNamespace av = "urn:schemas-sony-com:av";
System.Diagnostics.Debug.WriteLine(av);
<XElement> api_list = (List<XElement>)xDoc.Element(av + "X_ScalarWebAPI_DeviceInfo").Elements();
==EDIT==
Well, both solutions were ok, so I'm upvoting one and marking as answer the other :P
It was mentioned that the solution using only a 'local name' might cause false positive search results, so to be safe I'm using the first one. Thanks for help!

Element only returns elements directly beneath the current node. You need the to specify the entire path (note there are multiple namespaces):
XNamespace ns = "urn:schemas-upnp-org:device-1-0";
XNamespace av = "urn:schemas-sony-com:av";
var api_list = xDoc.Root.Element(ns + "device")
.Element(av + "X_ScalarWebAPI_DeviceInfo").Elements();

Using Xml Linq
XDocument doc = XDocument.Load(FILENAME);
XElement x_ScalarWebAPI_DeviceInfo = doc.Descendants().Where(x => x.Name.LocalName == "X_ScalarWebAPI_DeviceInfo").FirstOrDefault();
XNamespace ns = x_ScalarWebAPI_DeviceInfo.Name.Namespace;

The issue is indeed the Element or Elements methods only search the direct child elements. You can use Decendants() but you will get a collection, so you have to do First(expression) to het a single one.
But in the expression you can use .Name.LocalName to skip the whole namespace thing and look for just the name of the element.
For this question:
XDocument xDoc = XDocument.Parse(xml_text);
XElement x_ScalarWebAPI_DeviceInfo = doc.Descendants().First(x.Name.LocalName == "X_ScalarWebAPI_DeviceInfo");

Related

Cannot parse xml from Yahoo! Fantasy Sports with c#

I did some searching around the web and could not find the cause of my problem so I apologize if that has already been asked in another form I just did not understand.
My problem is that I am trying to parse the XML retrieved from Yahoo! Fantasy Sports but nothing seems to be working.
I have converted the XML I received (using a GET request with my credentials) into a string. Here it is for evaluation.
<?xml version="1.0" encoding="UTF-8" ?>
- <fantasy_content xml:lang="en-US" yahoo:uri="http://fantasysports.yahooapis.com/fantasy/v2/game/223/players" xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" time="5489.1560077667ms" copyright="Data provided by Yahoo! and STATS, LLC" refresh_rate="60" xmlns="http://fantasysports.yahooapis.com/fantasy/v2/base.rng">
- <game>
<game_key>223</game_key>
<game_id>223</game_id>
<name>Football PLUS</name>
<code>pnfl</code>
<type>full</type>
<url>http://football.fantasysports.yahoo.com/f2</url>
<season>2009</season>
- <players count="25">
- <player>
<player_key>223.p.8261</player_key>
<player_id>8261</player_id>
- <name>
<full>Adrian Peterson</full>
<first>Adrian</first>
<last>Peterson</last>
<ascii_first>Adrian</ascii_first>
<ascii_last>Peterson</ascii_last>
</name>
<editorial_player_key>nfl.p.8261</editorial_player_key>
<editorial_team_key>nfl.t.16</editorial_team_key>
<editorial_team_full_name>Minnesota Vikings</editorial_team_full_name>
<editorial_team_abbr>Min</editorial_team_abbr>
- <bye_weeks>
<week>9</week>
</bye_weeks>
<uniform_number>28</uniform_number>
<display_position>RB</display_position>
- <headshot>
<url>http://l.yimg.com/iu/api/res/1.2/7gLeB7TR77HalMeJv.iDVA--/YXBwaWQ9eXZpZGVvO2NoPTg2MDtjcj0xO2N3PTY1OTtkeD0xO2R5PTE7Zmk9dWxjcm9wO2g9NjA7cT0xMDA7dz00Ng--/http://l.yimg.com/j/assets/i/us/sp/v/nfl/players_l/20120913/8261.jpg</url>
<size>small</size>
</headshot>
<image_url>http://l.yimg.com/iu/api/res/1.2/7gLeB7TR77HalMeJv.iDVA--/YXBwaWQ9eXZpZGVvO2NoPTg2MDtjcj0xO2N3PTY1OTtkeD0xO2R5PTE7Zmk9dWxjcm9wO2g9NjA7cT0xMDA7dz00Ng--/http://l.yimg.com/j/assets/i/us/sp/v/nfl/players_l/20120913/8261.jpg</image_url>
<is_undroppable>1</is_undroppable>
<position_type>O</position_type>
- <eligible_positions>
<position>RB</position>
</eligible_positions>
<has_player_notes>1</has_player_notes>
</player>
- <player>
</players>
</game>
</fantasy_content>
The two methods I have tried are these (PLEASE NOTE: "xmlContent" is the string that contains the XML listed above):
1.)
XDocument chicken = XDocument.Parse(xmlContent);
var menus = from menu in chicken.Descendants("name")
select new
{
ID = menu.Element("name").Value,
};
and
2.)
byte[] encodedString = Encoding.UTF8.GetBytes(xmlContent);
MemoryStream ms = new MemoryStream(encodedString);
XmlDocument doc = new XmlDocument();
doc.Load(ms);
foreach (XmlNode row in doc).SelectNodes("//fantasy_content"))
{}
Basically, I get no results enumerated. I have a feeling I am missing some key steps here though. Any help is greatly appreciated. Thank you all.
UPDATE:
As per the awesome suggestions I received, I tried three more things. Since it is not working still, I did not listen very well. :) Actually, that is semi-accurate, please bear with my newbie attempt at working with XML here as I really am thankful for the responses. Here is how I am screwing up the great suggestions, can you offer another tip on what I missed? Thank you all again.
As per Jon Skeet's suggestion (this yields no results for me):
1.) XNamespace ns = "http://fantasysports.yahooapis.com/fantasy/v2/base.rng";
XDocument chicken = XDocument.Parse(xmlContent);
var menus = from menu in chicken.Descendants(ns + "fantasy_content")
select new
{
ID = menu.Element("name").Value,
};
As per the second suggestion (this throws me an error):
2.) var result = XElement.Load(xmlContent).Descendants().Where(x => x.Name.LocalName == "name");
As per the combinations of suggesting I need to identify the namespace and Yahoo! guide at: http://developer.yahoo.com/dotnet/howto-xml_cs.html
3.) xmlContent = oauth.AcquirePublicData(rtUrl, "GET");
byte[] encodedString = Encoding.UTF8.GetBytes(xmlContent);
MemoryStream ms = new MemoryStream(encodedString);
XmlDocument doc = new XmlDocument();
doc.Load(ms);
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("fantasy_content", "http://fantasysports.yahooapis.com/fantasy/v2/base.rng");
XmlNodeList nodes = doc.SelectNodes("/name", ns);
foreach (XmlNode node in nodes)
{
}
This is what's tripping you up:
xmlns="http://fantasysports.yahooapis.com/fantasy/v2/base.rng"
You're asking for elements in the unnamed namespace - but the elements default to the namespace shown above.
It's easy to fix that in LINQ to XML (and feasible but less simple in XmlDocument)
XNamespace ns = "http://fantasysports.yahooapis.com/fantasy/v2/base.rng";
var menus = chicken.Descendants(ns + "name")
...
Note that in your original method you're actually looking for name elements within the name elements - that's not going to work, but the namespace part is probably enough to get you going.
EDIT: It's not clear why you're using an anonymous type at all, but if you really want all the name element values from the document as ID properties in anonymous type instances, just use:
XNamespace ns = "http://fantasysports.yahooapis.com/fantasy/v2/base.rng";
var menus = chicken.Descendants(ns + "name")
.Select(x => new { ID = x.Value });
Note that there's no need to use Descendants(ns + "fantasy_content") as that's just selecting the root element.
Element name consists of two parts: xmlns(namespace) and localname. If xmlns is absent, name is equal to local name. So, you have to create name with namespace or ignore it
You can ignore namespace in your LINQ, just use LocalName
var result = XElement.Load(#"C:\fantasy_content.xml")
.Descendants()
.Where(x => x.Name.LocalName == "name")
.ToList();

XElement descendant not working \ XElement.Parse() [duplicate]

I'm a completly New to Linq2XML as I code to much lines to perform simple things, and in a simple project I wanted to give it a try...
I'm with this for 2 hours and nothing I do get's it right :(
I'm really, really thinking to go back to XmlNode-code-alike
The Task:
I send a SOAP Action to an ASMX service and I get the response as XML
I Parse the XML into a XDocument object
I try to get a list of nodes ... err! Problem!
as you can see from this screenshot
alt text http://www.balexandre.com/temp/2010-02-26_0038.png
my XDocument has a Node called TransactionInformationType witch is a Sequence, and I simple want to get all and retrieve the only 2 variables that I need (you can see the code commented) just below select c;
in the Watch window you can see that
doc.Descendants("TransactionInformationType")
returns nothing at all, and seeing by the content of the XDocument in the Text Visualizer, it does exist!
Anyone care to explain and help me passing this HUGE wall?
Thank you!
Added
XDocument content
Answer
the Response XML has
<gettransactionlistResponse xmlns="https://ssl.ditonlinebetalingssystem.dk/remote/payment">
and I must use this as Namespace!
turns out that, to retrieve values, I do need to use the XNamespace as well, so the final code looks like this:
// Parse XML
XDocument doc = XDocument.Parse(strResponse);
XNamespace ns = "https://ssl.ditonlinebetalingssystem.dk/remote/payment";
var trans = from item in doc.Descendants(ns + "TransactionInformationType")
select new TransactionInformationType
{
capturedamount = Convert.ToInt32(item.Element(ns + "capturedamount").Value),
orderid = item.Element(ns + "cardtypeid").Value
};
Thank you all for the help!
var result = doc.Descendants("TransactionInformationType");
selects all descendants in the XDocument that have element name "TransactionInformationType" and are in the empty namespace.
From you screenshot it seems the element you're trying to select is in the namespace "https://ssl.ditonlinebetalingssystem.dk/remote/payment" though.
You need to specify that explicitly:
XNamespace ns = "https://ssl.ditonlinebetalingssystem.dk/remote/payment";
↑↑ ↑
var result = doc.Descendants(ns + "TransactionInformationType");
This should solve you isssue (replace the namespace with the right URL):
XNamespace ns = "https://ssl.ditonline...";
doc.Descendants(ns + "TransactionInformationType");

Getting decendant node that contains ":"?

I have loaded a XML into a XDocument that looks something like this :
<MyXML xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyApp.Client.Main.GUI.Report">
<Wrapper xmlns:d2p1="http://schemas.datacontract.org/2004/07/MyApp.Business.Entity">
<d2p1:_MultipelAttributId>156</d2p1:_MultipelAttributId>
</Wrapper>
</MyXML>
Now I need to get the value of _MultipelAttributId but when stating this :
XElement element = (from cml2 in doc.Descendants("d2p1:_MultipelAttributId") select cml2).FirstOrDefault();
I get exception about the ":"?
So how do I get the valiue?
XNamespace ns = "http://schemas.datacontract.org/2004/07/MyApp.Business.Entity";
var element = xDoc.Descendants(ns + "_MultipelAttributId").FirstOrDefault();
The element name you're querying is not correct. Try this:
XElement element = (
from cml2 in doc.Descendants()
where cml2.Name.LocalName == "_MultipelAttributId"
select cml2).FirstOrDefault();
This MSDN article explains well how to work with namespaces in Linq to XML
http://msdn.microsoft.com/en-us/library/bb669152.aspx
XNamespace d2p1 = "http://schemas.datacontract.org/2004/07/MyApp.Business.Entity";
XElement multipelAttributId = doc.Descendants(d2p1 + "_MultipelAttributId").FirstOrDefault();
Notice that you can seamly create an XNamespace or an XName from a string because Microsoft have writen inplicit casts for these types.

Reading Elements within a Namespace

I have an XML file that looks like:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://www.someurl.com/somefile.xslt"?>
<AutoInsuranceClaim xmlns="http://www.someurl.com/schemas/AutoInsuranceClaim">
<Identification>
<BaseOwner>3</BaseOwner>
<BaseType>ABC123</BaseType>
<BaseTypeRef>471038341757</BaseTypeRef>
</Identification>
</AutoInsuranceClaim>
and I'm trying to read the Identification node. Here's my code:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"..\..\Data.xml");
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("ns", "http://www.someurl.com/schemas/AutoInsuranceClaim");
XmlNodeList nodeList = xmlDoc.SelectNodes(#"/ns:AutoInsuranceClaim/Identification", nsmgr);
Console.WriteLine("There are {0} nodes...", nodeList.Count);
I know I should get a least 1 value. My understanding of .NET XML parsing is that if you have a default namespace with no prefix, you have to create your own namespace. But this should have returned 1.
If not, what am I missing?
I might be grasping at straws here, but shouldn't you be namespacing both entities in your xpath expression?
XmlNodeList nodeList = xmlDoc.SelectNodes(#"/ns:AutoInsuranceClaim/ns:Identification", nsmgr);
XElement root = XElement.Load("Data.xml");
var identifications = root.Descendants()
.Where(x => x.Name.LocalName == "Identification")
.ToList()
The problem is that you're trying to find an Identification node without a namespace, but it will have defaulted to the same namespace as the parent due to the xmlns=... part. Try this:
var nodeList = xmlDoc.SelectNodes("/ns:AutoInsuranceClaim/ns:Identification",
nsmgr);
Having tried it myself, it printed a count of 1.
Personally I'd use LINQ to XML instead though, which makes namespace easier handling:
XDocument doc = XDocument.Load(#"..\..\Data.xml");
XNamespace ns = "http://www.someurl.com/schemas/AutoInsuranceClaim";
var nodes = doc.Root.Elements(ns + "Identification");

Reading XML with XDocument problem

I have a following XML (part of a .rdl report):
<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition">
<DataSources>
<DataSource Name="TMSSharepointDataSource">
<DataSourceReference>TMSSharepointDataSource</DataSourceReference>
<rd:DataSourceID>f06ffa33-238f-4d83-adfe-1eaa8df96e90</rd:DataSourceID>
</DataSource>
</DataSources>
</Report>
I try to parse and read it using following code:
byte[] fileContent = File.ReadAllBytes(#"path");
UTF8Encoding unicode = new UTF8Encoding();
string stringContent = unicode.GetString(fileContent);
XDocument xml = XDocument.Parse(stringContent);
XElement dsNode = xml.Root.Element("DataSources");
I can't figure out why is dsNode always null?
It's a namespace issue... you need to specify the namespace for the DataSources element. Fortunately, LINQ to XML makes this really easy:
XNamespace ns = "http://schemas.microsoft.com/sqlserver/" +
"reporting/2008/01/reportdefinition";
XElement dsNode = xml.Root.Element(ns + "DataSources");
Note the xmlns="http://..." part of the root element, which means that element and all elements below it which don't have an explicit namespace inherit that namespace.
You are probably missing a namespace reference. Your DataSources will inherit the namespace of the Report node and you will need both the namespace and element local name to generate an XName.
Alternatively you can do the following and skip the namespace check:
XElement dsNode =
xml
.Root
.DescendantNodes()
.Where(e => e.Name.LocalName.Equals("DataSources"))
.First();
This will return the first node where the local name is DataSources. In your example this will be the DataSources element.
Also, your loading of the document is very clumsy. I would suggest the following instead:
XDocument xml = XDocument.Load(File.OpenRead(#"path"));

Categories