How to get an specific node in xml with namespaces? - c#

I'm dealing to access an specific node from a XML Document. I realized that this one as a base namespace. Here is the example.
I'm interested to get the value of the node d:MediaUrl from all descendents node (entry). And I haven't accomplished that.
When I debug the variable iterator 'i', I can see that the XML includes the default namespace again, something like:
<entry xmlns="http://schemas.microsoft.com.ado/..."
And also I have to include the another namespace called 'd'.
What can I do to access to that particular nodes?
This is what I have.
var doc = XDocument.Parse(result);
string BASE_NS = "http://www.w3.org/2005/Atom";
string d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
var query = from i in doc.Descendants(XName.Get("entry", BASE_NS))
select new Image()
{
Url = i.Element(XName.Get("MediaUrl", BASE_NS)).Value
};
var results = query.ToList();

I would suggest using XNamespace rather than XName (personal preference, mainly - as that's how I've always dealt with namespaces in LINQ to XML). To me it's less effort to set up the namespaces in advance and then use Element(NS + "element name") than to useXName.Get(though usingXName.Get` is perfectly fine if that's what you want to do.
If you want to get a all the "MediaUrl" elements for each entry, then I'd do something like this:
XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
var query = (from i in doc.Descendants(d + "MediaUrl")
select new Image()
{
Url = i.Value
}).ToList();
If you want to get only one of them, then you need to do something a little different, depending on which one you wanted to get.
For the properties MediaUrl:
XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
var query = (from i in doc.Descendants(m + "properties")
select new Image()
{
Url = i.Element(d + "MediaUrl").Value
}).ToList();
For the Thumbnail MediaUrl:
XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
var query = (from i in doc.Descendants(d + "Thumbnail")
select new Image()
{
Url = i.Element(d + "MediaUrl").Value
}).ToList();
The key here is to use the namespace in conjunction with the element name in order to retrieve it.

var query = from i in doc.Descendants("{full namespace for prefix d}MediaUrl")
select new Image()
{
Url = i.Value
};

Related

how to get value from xml by Linq

i was reading huge xml file of 5GB size by using the following code, and i was success to get the first element Testid but failed to get another element TestMin coming under different namespace
this is the xml i am having
which i am getting as null
.What is wrong here?
EDIT
GMileys answer giving error like The ':' character, hexadecimal value 0x3A, cannot be included in a name
The element es:qRxLevMin is a child element of xn:attributes, but it looks like you are trying to select it as a child of xn:vsDataContainer, it is a grandchild of that element. You could try changing the following:
var dataqrxlevmin = from atts in pin.ElementsAfterSelf(xn + "VsDataContainer")
select new
{
qrxlevmin = (string)atts.Element(es + "qRxLevMin"),
};
To this:
var dataqrxlevmin = from atts in pin.Elements(string.Format("{0}VsDataContainer/{1}attributes", xn, es))
select new
{
qrxlevmin = (string)atts.Element(es + "qRxLevMin"),
};
Note: I changed your string concatenation to use string.Format for readability purposes, either is technically fine to use, but string.Format is a better approach.
What about this approach?
XDocument doc = XDocument.Load(path);
XName utranCellName = XName.Get("UtranCell", "un");
XName qRxLevMinName = XName.Get("qRxLevMin", "es");
var cells = doc.Descendants(utranCellName);
foreach (var cell in cells)
{
string qRxLevMin = cell.Descendants(qRxLevMinName).FirstOrDefault();
// Do something with the value
}
try this code which is very similar to your code but simpler.
using (XmlReader xr = XmlReader.Create(path))
{
xr.MoveToContent();
XNamespace un = xr.LookupNamespace("un");
XNamespace xn = xr.LookupNamespace("xn");
XNamespace es = xr.LookupNamespace("es");
while (!xr.EOF)
{
if(xr.LocalName != "UtranCell")
{
xr.ReadToFollowing("UtranCell", un.NamespaceName);
}
if(!xr.EOF)
{
XElement utranCell = (XElement)XElement.ReadFrom(xr);
}
}
}
actually namespace was the culprit,what i did is first loaded the small section i am getting from.Readform method in to xdocument,then i removed all the namespace,then i took the value .simple :)

Stuck on basic Linq to XML query

I'm trying to extract the information from the namecheap sandbox api and can't figure out why my linq queries aren't working.
Here's a sample response.
XML
<ApiResponse Status="OK" xmlns="http://api.namecheap.com/xml.response">
<Errors />
<Warnings />
<RequestedCommand>namecheap.domains.check</RequestedCommand>
<CommandResponse>
<DomainCheckResult Domain="google.com" Available="false" />
</CommandResponse>
<Server>WEB1-SANDBOX1</Server>
<GMTTimeDifference>--4:00</GMTTimeDifference>
<ExecutionTime>0.875</ExecutionTime>
</ApiResponse>
C#
var doc = XDocument.Load(url);
var response = (
from r in doc.Root.Descendants("ApiResponse")
where 1==1
select new {
Errors = r.Element("Errors").Value,
Warnings = r.Element("Warnings").Value,
RequestedCommand = r.Element("RequestedCommand").Value,
CommandResponse = r.Element("CommandResponse").Value,
Server = r.Element("Server").Value
}
);
I've also tried this query with the same doc just to see if a simple example worked.
var test = doc.Descendants("RequestedCommand").First().Value;
But both return null. So where am I going wrong? I'll eventually need to get at the top level elements and the deeper elements within CommandResponse. Any help with that would also be appreciated.
UPDATE
As Jon's answer mentioned, it was mainly an issue with not using the namespace when referencing the various elements. Also used doc.Elements() rather then doc.Root. Descendants().
Here's an updated working version.
XNamespace ns = "http://api.namecheap.com/xml.response";
var response = (
from r in doc.Elements()
select new
{
Errors = r.Element(ns + "Errors").Value,
Warnings = r.Element(ns + "Warnings").Value,
RequestedCommand = r.Element(ns + "RequestedCommand").Value,
CommandResponse = r.Element(ns + "CommandResponse").Value,
Server = r.Element(ns + "Server").Value
}
);
The problem is that you're not using the namespace when you're looking for elements, descendants etc:
XNamespace ns = "http://api.namecheap.com/xml.response";
var doc = XDocument.Load(url);
var response = doc.Root
.Descendants(ns + "ApiResponse")
.Select(r => new {
Errors = r.Element(ns + "Errors").Value,
...
});
(Note that you never need where 1 == 1 in LINQ... I've changed this from query expression syntax as it wasn't giving you anything.)
The namespace is inherited from the <ApiResponse> element as the default namespace for all the other elements, as it's just xmlns=... rather than specifying an alias.
Also note that if you've shown us the whole XML document, then the above won't find any elements, as you're asking for ApiReponse elements below the root element, whereas it is the root element.
I just got Skeeted ;)
Here's something I did in linqpad to get you one of the elements in the XML
var myxml = #"<ApiResponse Status=""OK"" xmlns=""http://api.namecheap.com/xml.response"">
<Server>WEB1-SANDBOX1</Server>
<Errors />
<Warnings />
<RequestedCommand>namecheap.domains.check</RequestedCommand>
<CommandResponse>
<DomainCheckResult Domain=""google.com"" Available=""false"" />
</CommandResponse>
<GMTTimeDifference>--4:00</GMTTimeDifference>
<ExecutionTime>0.875</ExecutionTime>
</ApiResponse>";
//myxml.Dump();
XNamespace p = "http://api.namecheap.com/xml.response";
var doc1 = XElement.Parse(myxml);
var x = from n in doc1.Elements(p + "Server") select n;
x.First().Value.Dump();

Having issue parsing xml with linq to xml

I am having a problem parsing xml that I receive from Web Service.
The xml looks very simple:
<Result xsi:schemaLocation="urn:yahoo:developer http://developer.yahooapis.com/TimeService/V1/GetTimeResponse.xsd" type="web"><Timestamp>1320677359</Timestamp></Result>
But when I try to parse it with following code I am getting no return results.
XDocument doc = XDocument.Load("http://developer.yahooapis.com/TimeService/V1/getTime?appid=StackSolution");
var datestamp = from ds in doc.Descendants("Result")
select new { currentstamp = ds.Element("Timestamp").Value };
Is there a solution or way to parse it?
Thanks you in advance
You have a couple issues: First, the Result node isn't a descendant. It's the root. Second, you ran into the most common issue when using LINQ to XML - you forgot the namespace. The following should give you what you need:
XElement doc = XElement.Load("http://developer.yahooapis.com/TimeService/V1/getTime?appid=StackSolution");
XNamespace ns = "urn:yahoo:developer";
var datestamp = from ds in doc.DescendantsAndSelf(ns + "Result")
select new { currentstamp = ds.Element(ns + "Timestamp").Value };
Note, this produces an IEnumerable. If you only want the datestamp, consider using FirstOrDefault instead. You may be able to make this simpler by just doing the following:
XElement doc = XElement.Load("http://developer.yahooapis.com/TimeService/V1/getTime?appid=StackSolution");
XNamespace ns = "urn:yahoo:developer";
var datestamp = doc.Element(ns + "Timestamp").Value;
This method avoids the namespace issue using LocalName (unqualified identifier).
var datestamp = doc.Root.Descendants().Where(c => c.Name.LocalName.Equals("Timestamp")).FirstOrDefault().FirstNode.ToString()

A simple question about LINQ to XML

<root xmlns:h="http://www.w3.org/TR/html4/"
xmlns:f="http://www.w3schools.com/furniture">
<h:table>
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>
<f:table>
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
</root>
I am trying to practice LinqToXml but i can't figure out what i wanted.Simply how can i query table elements which has h or f namespace ?
This was what i tried .Also i tried different ones but didn't work.
var query = from item in XDocument.Parse(xml).Elements(ns + "table")
select item;
This won't work because you're missing the root element from your query. This would work:
XNamespace ns = "http://www.w3schools.com/furniture";
var query = XDocument.Parse(xml).Element("root").Elements(ns + "table");
Now if the problem is that you want to find all "table" elements regardless of the namespace, you'd need something like this:
var query = XDocument.Parse(xml)
.Element("root")
.Elements()
.Where(element => element.Name.LocalName == "table");
(EDIT: As noted, you could use XDocument.Root to get to the root element if you want to. The important point is that trying to get to the table element directly from the document node itself won't work.)
Namespace prefixes are not guaranteed to be a particular letter or string. The best approach would be to search by the qualified namespace.
This would get all direct child nodes of XElement xml where the namespace is uri:namespace...
var selectedByNamespace = from element in xml.Elements()
where element.Name.NamespaceName == "uri:namespace"
select element;
Another option would be to select the elements based on the fully qualified name.
var ns = "{uri:namespace}";
var selectedElements = xml.Elements(ns + "table");

Use Linq to Xml with Xml namespaces

I have this code :
/*string theXml =
#"<Response xmlns=""http://myvalue.com""><Result xmlns:a=""http://schemas.datacontract.org/2004/07/My.Namespace"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><a:TheBool>true</a:TheBool><a:TheId>1</a:TheId></Result></Response>";*/
string theXml = #"<Response><Result><TheBool>true</TheBool><TheId>1</TheId></Result></Response>";
XDocument xmlElements = XDocument.Parse(theXml);
var elements = from data in xmlElements.Descendants("Result")
select new {
TheBool = (bool)data.Element("TheBool"),
TheId = (int)data.Element("TheId"),
};
foreach (var element in elements)
{
Console.WriteLine(element.TheBool);
Console.WriteLine(element.TheId);
}
When I use the first value for theXml, the result is null, whereas with the second one, I have good values ...
How to use Linq to Xml with xmlns values ?
LINQ to XML methods like Descendants and Element take an XName as an argument. There is a conversion from string to XName that is happening automatically for you. You can fix this by adding an XNamespace before the strings in your Descendants and Element calls. Watch out because you have 2 different namespaces at work.
string theXml =
#"true1";
//string theXml = #"true1";
XDocument xmlElements = XDocument.Parse( theXml );
XNamespace ns = "http://myvalue.com";
XNamespace nsa = "http://schemas.datacontract.org/2004/07/My.Namespace";
var elements = from data in xmlElements.Descendants( ns + "Result" )
select new
{
TheBool = (bool) data.Element( nsa + "TheBool" ),
TheId = (int) data.Element( nsa + "TheId" ),
};
foreach ( var element in elements )
{
Console.WriteLine( element.TheBool );
Console.WriteLine( element.TheId );
}
Notice the use of ns in Descendants and nsa in Elements
You can pass an XName with a namespace to Descendants() and Element(). When you pass a string to Descendants(), it is implicitly converted to an XName with no namespace.
To create a XName in a namespace, you create a XNamespace and concatenate it to the element local-name (a string).
XNamespace ns = "http://myvalue.com";
XNamespace nsa = "http://schemas.datacontract.org/2004/07/My.Namespace";
var elements = from data in xmlElements.Descendants( ns + "Result")
select new
{
TheBool = (bool)data.Element( nsa + "TheBool"),
TheId = (int)data.Element( nsa + "TheId"),
};
There is also a shorthand form for creating a XName with a namespace via implicit conversion from string.
var elements = from data in xmlElements.Descendants("{http://myvalue.com}Result")
select new
{
TheBool = (bool)data.Element("{http://schemas.datacontract.org/2004/07/My.Namespace}TheBool"),
TheId = (int)data.Element("{http://schemas.datacontract.org/2004/07/My.Namespace}TheId"),
};
Alternatively, you could query against XElement.Name.LocalName.
var elements = from data in xmlElements.Descendants()
where data.Name.LocalName == "Result"
I have several namespaces listed at the top of an XML document, I don't really care about which elements are from which namespace. I just want to get the elements by their names. I've written this extension method.
/// <summary>
/// A list of XElement descendent elements with the supplied local name (ignoring any namespace), or null if the element is not found.
/// </summary>
public static IEnumerable<XElement> FindDescendants(this XElement likeThis, string elementName) {
var result = likeThis.Descendants().Where(ele=>ele.Name.LocalName==elementName);
return result;
}
I found the following code to work fine for reading attributes with namespaces in VB.NET:
MyXElement.Attribute(MyXElement.GetNamespaceOfPrefix("YOUR_NAMESPACE_HERE") + "YOUR_ATTRIB_NAME")
Hope this helps someone down the road.

Categories

Resources