How to read colon in xml file using c# linq - c#

How can I read colon in xml file using c# linq
My code in c#
XDocument xdocc = XDocument.Load(files, LoadOptions.SetLineInfo);
var mml_hi_it = xdocc.Descendants("mml:hi").Where(s => (string)s.Attribute("rend").Value == "it");

The mml literal indicates the namespace used in your xml. You should be able to find the definition in the root node. For example, based on your comment, your root tag looks like following.
<article article-type="research-article" dtd-version="1.1" xml:lang="en" xmlns:mml="w3.org/1998/Math/MathML" xmlns:xlink="w3.org/1999/xlink" xmlns:oasis="niso.org/standards/z39-96/ns/oasis-exchange/table">
In order to access Element with namespace, you need to specify the namespace using XNamespace. For example,
XNamespace mml = "w3.org/1998/Math/MathML";
var mml_hi_it = xdocc.Descendants(mml + "hi").Where(s => (string)s.Attribute("rend").Value == "it");

Related

how to add xmlns attribute to an existing xml document

I have existing xml document.
e.g
<Test>
<A />
</Test>
I load this xml into XDocument. I need to add attribute xmlns to this document and save it with this attribute.
var xml = new XDocument.Load("c:\\filePath.xml");
When I'm trying this:
xml.Root.SetAttributeValue("xmlns", "http://namespaceuri");
I'm getting exception:
System.Xml.XmlException: The prefix '' cannot be redefined from 'http://namespaceuri' to within the same start element tag.
thanks
You need to set the names to be in the namespace as well:
XNamespace ns = "http://namespaceuri";
foreach (var element in xml.Descendants().ToList())
{
element.Name = ns + element.Name.LocalName;
}
xml.Root.SetAttributeValue("xmlns", ns.ToString());
Basically you're trying to move all the elements to that namespace and make it the default namespace for the root element down. You can't change the default namespace while leaving the element itself in a different-but-unqualified namespace.
Using the code above with your sample XML (fixed to close A) ends up with:
<Test xmlns="http://namespaceuri">
<A />
</Test>
Note that this code will change the namespace of all elements. If you want to be more selective, you should add a Where call after the xml.Descendants() call, e.g.
foreach (var element in xml.Descendants()
.Where(x => x.Name.Namespace == XNamespace.None)
.ToList())

Parsing complex XML with C#

I am trying to parse a complex XML with C#, I am using Linq to do it. Basically, I am doing a request to a server and I get XML, this is the code:
XElement xdoc = XElement.Parse(e.Result);
this.newsList.ItemsSource =
from item in xdoc.Descendants("item")
select new ArticlesItem
{
//Image = item.Element("image").Element("url").Value,
Title = item.Element("title").Value,
Description = this.Strip(item.Element("description").Value).Substring(0, 200).ToString()
}
And this is the XML structure:
<item>
<test:link_id>1282570</test:link_id>
<test:user>SLAYERTANIC</test:user>
<title>aaa</title>
<description>aaa</description>
</item>
How I can access to the property test:link_id for example?
Thanks!
Currently your XML is invalid since the test namespace is not declared, you can declare it like this:
<item xmlns:test="http://foo.bar">
<test:link_id>1282570</test:link_id>
<test:user>SLAYERTANIC</test:user>
<title>aaa</title>
<description>aaa</description>
</item>
Having this you can use XNamespace to qualify the XML element you want with the correct namespace:
XElement xdoc = XElement.Parse(e.Result);
XNamespace test = "http://foo.bar";
this.newsList.ItemsSource = from item in xdoc.Descendants("item")
select new ArticlesItem
{
LinkID = item.Element(test + "link_id").Value,
Title = item.Element("title").Value,
Description = this.Strip(item.Element("description").Value).Substring(0, 200).ToString()
}
To write a query on XML that is in a
namespace, you must use XName objects
that have the correct namespace. For
C#, the most common approach is to
initialize an XNamespace using a
string that contains the URI, then use
the addition operator overload to
combine the namespace with the local
name.
To retrieve the value of the link_id element you will need to declare and use an XML namespace for the test:link element.
Since you did not show the namespace declaration in your example XML, I am going to assume it is declared somewhere elese in the XML document. You need to locate the namespace declaration in the XML ( something like xmlns:test="http://schema.example.org" ) which is often declared in the root of the XML document.
After you know this, you can do the following to retrieve the value of the link_id element:
XElement xdoc = XElement.Parse(e.Result);
XNamespace testNamespace = "http://schema.example.org";
this.newsList.ItemsSource = from item in xdoc.Descendants("item")
select new ArticlesItem
{
Title = item.Element("title").Value,
Link = item.Element(testNamespace + "link_id").Value,
Description = this.Strip(item.Element("description").Value).Substring(0, 200).ToString()
}
See the XNamespace and Namespaces in C#, and How to: Write Queries on XML in Namespaces for further information.

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

Using LINQ to XML to Process XML in Multiple Namespaces

I'm trying to parse results from the YouTube API. I'm getting the results correctly as a string, but am unable to parse it correctly.
I followed suggestions on a previous thread, but am not getting any results.
My sample code is:
string response = youtubeService.GetSearchResults(search.Term, "published", 1, 50);
XDocument xDoc = XDocument.Parse(response, LoadOptions.SetLineInfo);
var list = xDoc.Descendants("entry").ToList();
var entries = from entry in xDoc.Descendants("entry")
select new
{
Id = entry.Element("id").Value,
Categories = entry.Elements("category").Select(c => c.Value)
//Published = entry.Element("published").Value,
//Title = entry.Element("title").Value,
//AuthorName = entry.Element("author").Element("name").Value,
//Thumnail = entry.Element("media:group").Elements("media:thumnail").ToList().ElementAt(0)
};
foreach (var entry in entries)
{
// entry.Id and entry.Categories available here
}
The problem is that entries has a count of 0 even though the XDocument clearly has the valid values.
The value of the response variable (Sample XML) can be seen here: http://snipt.org/lWm
(FYI: The youTube schema is listed here: http://code.google.com/apis/youtube/2.0/developers_guide_protocol_understanding_video_feeds.html)
Can anyone tell me what I'm doing wrong here?
All the data is in the "http://www.w3.org/2005/Atom" namespace; you need to use this throughout:
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
...
from entry in xDoc.Descendants(ns + "entry")
select new
{
Id = entry.Element(ns + "id").Value,
Categories = entry.Elements(ns + "category").Select(c => c.Value)
...
};
etc (untested)
When you see prefix:name, it means that name is in the namespace whose prefix has been declared as prefix. If you look at the top of the document, you'll see an xmlns:media=something. The something is the namespace used for anything with the prefix media.
This means you need to create an XNamespace for each of the namespaces you need to reference:
XNamespace media = XNamespace.Get("http://search.yahoo.com/mrss/");
and then use media for the names in that namespace:
media + "group"
The namespaces in this document are:
xmlns="http://www.w3.org/2005/Atom"
xmlns:app="http://www.w3.org/2007/app"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
xmlns:gd="http://schemas.google.com/g/2005"
xmlns:gml="http://www.opengis.net/gml"
xmlns:yt="http://gdata.youtube.com/schemas/2007"
xmlns:georss="http://www.georss.org/georss"
You need to set the namespace.
Creating an XName in a Namespace
As with XML, an XName can be in a namespace, or it can be in no namespace.
For C#, the recommended approach for creating an XName in a namespace is to declare the XNamespace object, then use the override of the addition operator.
http://msdn.microsoft.com/en-us/library/system.xml.linq.xname.aspx

Can I avoid having to use fully-qualified element names in LINQ to XML?

Say I call XElement.Parse() with the following XML string:
var xml = XElement.Parse(#"
<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Owner>
<ID>7c75442509c41100b6a413b88b523bd6f46554cdbee5b6cbe27bc08cb3f6a865</ID>
<DisplayName>me</DisplayName>
</Owner>
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
...
");
When it comes time to query the element, I'm forced to use fully-qualified element names because that XML document contains an xmlns attribute in its root. This requires cumbersome creations of XName instances:
var AWS_XMLNS = "http://s3.amazonaws.com/doc/2006-03-01/";
var ownerElement = xml.Element(XName.Get("AccessControlPolicy", AWS_XMLNS)).Element(XName.Get("Owner", AWS_XMLNS));
When what I really want is simply,
var ownerElement = xml.Element("AccessControlPolicy").Element("Owner");
Is there a way to make LINQ to XML assume a specific namespace so I don't have to keep specifying it?
You could simplify by using
XNamespace ns = "http://s3.amazonaws.com/doc/2006-03-01/";
var ownerElement = xml.Element(ns + "AccessControlPolicy").Element(ns + "Owner");
I don't think you can (see Jon Skeet's comment), but there are a few tricks you can do.
1) create an extension method that appends the XNamespace to your string
2) Use VB?!?

Categories