Reading child nodes from xml string using C#, LINQ - c#

- <entry xml:base="http://testserver.windows.net/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/"datetime'2015-08-30T00%3A04%3A02.9193525Z'"">
<id>http://testserver.windows.net/Players(PartitionKey='zzz',RowKey='000125')</id>
<category term="testServer.Players" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" title="Players" href="Players(PartitionKey='zzz',RowKey='000125')" />
<title />
<updated>2014-04-30T00:53:42Z</updated>
- <author>
<name />
</author>
- <content type="application/xml">
- <m:properties>
<d:PartitionKey>zzz</d:PartitionKey>
<d:RowKey>000125</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">2014-04-30T00:04:02.9193525Z</d:Timestamp>
<d:Name>Black color</d:Name>
<d:Comments>Test comments</d:Comments>
</m:properties>
</content>
</entry>
How can I read "m:properties" descendants using C# or LINQ.
This xml string is stored in variable of type XElement

You can use combination of XNamespace+"element local name" to reference element in namespace, for example :
XElement myxelement = XElement.Parse("your XML string here");
XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
List<XElement> properties = myxelement.Descendants(m+"properties").ToList();

I think this could show you how to use Linq to XML
read the data from XML Structure using c#
If anything else makes problems, just debug a little, see what you get from L2X operation, and move a step deeper trough data tree.

Using Linq2XML
var xDoc = XDocument.Load(filename);
var dict = xDoc.Descendants("m:properties")
.First()
.Attributes()
.ToDictionary(x => x.Name, x => x.Value);

Setup namespace manager. Note that .net library does not support default namespace, so I added prefix "ns" to default namespace.
use xpath or linq to query xml. Following example uses xpath.
XmlNamespaceManager NamespaceManager = new XmlNamespaceManager(new NameTable());
NamespaceManager.AddNamespace("base", "http://testserver.windows.net/");
NamespaceManager.AddNamespace("d", "http://schemas.microsoft.com/ado/2007/08/dataservices");
NamespaceManager.AddNamespace("m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
NamespaceManager.AddNamespace("ns", "http://www.w3.org/2005/Atom"); XDocument doc = XDocument.Parse(XElement);
var properties = doc.XPathSelectElement("/ns:entry/ns:content/m:properties", NamespaceManager);

Related

Read xml descendants collection from xml string [duplicate]

- <entry xml:base="http://testserver.windows.net/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/"datetime'2015-08-30T00%3A04%3A02.9193525Z'"">
<id>http://testserver.windows.net/Players(PartitionKey='zzz',RowKey='000125')</id>
<category term="testServer.Players" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" title="Players" href="Players(PartitionKey='zzz',RowKey='000125')" />
<title />
<updated>2014-04-30T00:53:42Z</updated>
- <author>
<name />
</author>
- <content type="application/xml">
- <m:properties>
<d:PartitionKey>zzz</d:PartitionKey>
<d:RowKey>000125</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">2014-04-30T00:04:02.9193525Z</d:Timestamp>
<d:Name>Black color</d:Name>
<d:Comments>Test comments</d:Comments>
</m:properties>
</content>
</entry>
How can I read "m:properties" descendants using C# or LINQ.
This xml string is stored in variable of type XElement
You can use combination of XNamespace+"element local name" to reference element in namespace, for example :
XElement myxelement = XElement.Parse("your XML string here");
XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
List<XElement> properties = myxelement.Descendants(m+"properties").ToList();
I think this could show you how to use Linq to XML
read the data from XML Structure using c#
If anything else makes problems, just debug a little, see what you get from L2X operation, and move a step deeper trough data tree.
Using Linq2XML
var xDoc = XDocument.Load(filename);
var dict = xDoc.Descendants("m:properties")
.First()
.Attributes()
.ToDictionary(x => x.Name, x => x.Value);
Setup namespace manager. Note that .net library does not support default namespace, so I added prefix "ns" to default namespace.
use xpath or linq to query xml. Following example uses xpath.
XmlNamespaceManager NamespaceManager = new XmlNamespaceManager(new NameTable());
NamespaceManager.AddNamespace("base", "http://testserver.windows.net/");
NamespaceManager.AddNamespace("d", "http://schemas.microsoft.com/ado/2007/08/dataservices");
NamespaceManager.AddNamespace("m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
NamespaceManager.AddNamespace("ns", "http://www.w3.org/2005/Atom"); XDocument doc = XDocument.Parse(XElement);
var properties = doc.XPathSelectElement("/ns:entry/ns:content/m:properties", NamespaceManager);

Extract a node from xml response

Below is my response generated from a webservice.
I want to do such that I want only PresentationElements node from this response.
Any help how can I achieve this query?
<?xml version="1.0"?>
<GetContentResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ExtensionData />
<GetContentResult>
<ExtensionData />
<Code>0</Code>
<Value>Success</Value>
</GetContentResult>
<PresentationElements>
<PresentationElement>
<ExtensionData />
<ContentReference>Product View Pack</ContentReference>
<ID>SHOPPING_ELEMENT:10400044</ID>
<Name>View Pack PE</Name>
<PresentationContents>
<PresentationContent>
<ExtensionData />
<Content>View Pack</Content>
<ContentType>TEXT</ContentType>
<Language>ENGLISH</Language>
<Medium>COMPUTER_BROWSER</Medium>
<Name>Name</Name>
</PresentationContent>
<PresentationContent>
<ExtensionData />
<Content>Have more control of your home's security and lighting with View Pack from XFINITY Home.</Content>
<ContentType>TEXT</ContentType>
<Language>ENGLISH</Language>
<Medium>COMPUTER_BROWSER</Medium>
<Name>Description</Name>
</PresentationContent>
<PresentationContent>
<ExtensionData />
<Content>/images/shopping/devices/xh/view-pack-2.jpg</Content>
<ContentType>TEXT</ContentType>
<Language>ENGLISH</Language>
<Medium>COMPUTER_BROWSER</Medium>
<Name>Image</Name>
</PresentationContent>
<PresentationContent>
<ExtensionData />
<Content>The View Pack includes:
2 Lighting / Appliance Controllers
2 Indoor / Outdoor Cameras</Content>
<ContentType>TEXT</ContentType>
<Language>ENGLISH</Language>
<Medium>COMPUTER_BROWSER</Medium>
<Name>Feature1</Name>
</PresentationContent>
</PresentationContents>
</PresentationElement>
</PresentationElements>
</GetContentResponse>
You can use XPath extensions
var xdoc = XDocument.Parse(response);
XElement presentations = xdoc.XPathSelectElement("//PresentationElements");
You may use the System.Xml.Linq.XDocument:
//Initialize the XDocument
XDocument doc = XDocument.Parse(yourString);
//your query
var desiredNodes = doc.Descendants("PresentationElements");
Pretty easy, have you tried:
XDocument xml = XDocument.Load("... xml");
var nodes = (from n in xml.Descendants("PresentationElements")
select n).ToList();
You could also project each individual node to an anonymous type using something like:
select new
{
ContentReference = (string)n.Element("ContentReference").Value,
.... etc
}

How to modify an external xml file and save it locally in C#

I'm new to C# and want to manipulate a external xml file. Here is that file:
<results>
<root />
<category id="" title="" />
<category />
<category />
</results>
I want this to be modified something like:
<results>
<root />
<categories>
<category id="" title=""/>
<category />
<category />
</categories>
</results>
This works, it replaces all of the elements named category found directly under the root element (root element is results) and adds new element named categories. category elements are then added to categories and category elements are removed from under the results element. In the end categories element is added. You can also save the document by calling it's Save method:
XDocument doc = XDocument.Load("Data.xml");
var categoriesElement = new XElement("categories");
var categoryElements = doc.Root.Elements("category");
foreach(var el in categoryElements.ToList())
{
categoriesElement.Add(new XElement(el));
el.Remove();
}
doc.Element("results").Add(categoriesElement);
//doc.Save(<filepath>);
XElement elem = XElement.Parse(xml);
elem = new XElement("results",
new XElement("root", elem.Element("root").Value),
new XElement("categories", elem.Descendants("category"))
);
Ideally the xml can be transformed using xslt. Basics on xslt transforation can be found below,
http://support.microsoft.com/kb/307322
http://www.w3schools.com/xsl/
Using xslt makes you solution or code more managable. Hope this helps

How to query XElement with two namespaces

I'm trying to find the inner text value of an element using LINQ-to-XML (an XElement object). I make my service call and get an XML response back that I've successfully loaded into an XElement object. I want to extract the inner text of one of the elements - however, every time I try to do this, I get a null result.
I feel like I'm missing something super-simple, but I'm fairly new to LINQ-to-XML. Any help is appreciated.
I'm trying to get the inner text value of the StatusInfo/Status element. Here's my XML document that's returned:
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom">
<title type="text">My Response</title>
<id>tag:foo.com,2012:/bar/06468dfc-32f7-4650-b765-608f2b852f22</id>
<author>
<name>My Web Services</name>
</author>
<link rel="self" type="application/atom+xml" href="http://myServer/service.svc/myPath" />
<generator uri="http://myServer" version="1">My Web Services</generator>
<entry>
<id>tag:foo.com,2012:/my-web-services</id>
<title type="text" />
<updated>2012-06-27T14:22:42Z</updated>
<category term="tag:foo.com,2008/my/schemas#system" scheme="tag:foo.com,2008/my/schemas#type" />
<content type="application/vnd.my.webservices+xml">
<StatusInfo xmlns="tag:foo.com,2008:/my/data">
<Status>Available</Status> <!-- I want the inner text -->
</StatusInfo>
</content>
</entry>
</feed>
Here's a snippet of code that I'm using to extract the value (which doesn't work):
XElement root = XElement.Load(responseReader);
XNamespace tag = "tag:foo.com,2008:/my/data";
var status = (from s in root.Elements(tag + "Status")
select s).FirstOrDefault();
My status variable is always null. I've tried several variations on this, but to no avail. The part that's confusing me is the namespace -- tag and 2008 are defined. I don't know if I'm handling this correctly or if there's a better way to deal with this.
Also, I don't have control over the XML schema or the structure of the XML. The service I'm using is out of my control.
Thanks for any help!
Try Descendants() instead of Elements():
XElement x = XElement.Load(responseReader);
XNamespace ns = "tag:foo.com,2008:/my/data";
var status = x.Descendants(ns + "Status").FirstOrDefault().Value;
There are 2 Namespaces in the feed:
the Atom namespace
the tag namespace
The outer xml needs to use the Atom namespace, while a portion of the inner xml needs to use the tag namespace. i.e.,
var doc = XDocument.Load(responseReader);
XNamespace nsAtom = "http://www.w3.org/2005/Atom";
XNamespace nsTag = "tag:foo.com,2008:/my/data";
// get all entry nodes / use the atom namespace
var entry = doc.Root.Elements(nsAtom + "entry");
// get all StatusInfo elements / use the atom namespace
var statusInfo = entry.Descendants(nsTag + "StatusInfo");
// get all Status / use the tag namespace
var status = statusInfo.Elements(nsTag + "Status");
// get value of all Status
var values = status.Select(x => x.Value.ToString()).ToList();

Reading the xml below shows error in c#

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
<w:body>
<w:customXml w:uri="Sample" w:element="note">
<w:p w:rsidR="00B06944" w:rsidRDefault="0051608D" w:rsidP="000E0B9F">
<w:customXml w:element="to">
<w:r w:rsidR="000E0B9F" w:rsidRPr="00B84BAE">
<w:rPr>
<w:b/>
<w:bCs/>
</w:rPr>
<w:t xml:space="preserve">Saran </w:t>
</w:r>
</w:customXml>
</w:body>
</w:document>
as I want to read the node < w:r >
for this i am writing the below code
XmlDocument doc = new XmlDocument();
doc.Load("\\document.xml");
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(doc.NameTable);
XmlNode node = doc.SelectSingleNode("/w:body/w:customXml/w:r", namespaceManager);
which gives:
The error shown in this line is Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.
How can I read the Xml
You need to tell namespaceManager about the meaning of the alias w. It sounds like this is redundant (from the file), but it is not the case that the aliases you want for query are necessarily those from the source, since the meaning of the file is identical if I replace all the w aliases in the source document with foo (as long as I also define foo:xmlns to the be same). Or I could use xmlns instead of aliases throughout.
Hence:
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(doc.NameTable);
namespaceManager.Add("w",
"http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XmlNode node = doc.SelectSingleNode("/w:body/w:customXml/w:r", namespaceManager);
This allows your query to succeed identically, regardless of the specific aliases used in the source.
It doesn't give me that error - it gives me an error because the <w:p> tag doesn't have a closing tag, and neither does the outer <w:customXml>. Once those are fixed, the document loads correctly.
There's then the matter of getting the right query. Marc has addressed this in his answer, but personally I'd use the methods in LINQ to XML instead:
var doc = XDocument.Load("test.xml");
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
var element = doc.Root.Element(w + "body")
.Element(w + "customXml")
.Element(w + "p")
.Element(w + "customXml")
.Element(w + "r");
This finds the element correctly. Note that it's not the same as your original XPath even aside from the namespaces - look carefully at your XML; it doesn't have a <w:r> element inside the outer <w:customXml> element.
your xml is not valid. you have no closing w:p tag...

Categories

Resources