I'm loading an xml feed from youtube into xelement like so:
XElement element = XElement.Load(url);
This is fine and I get a document that looks like this:
<?xml version='1.0' encoding='UTF-8' ?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/' xmlns:opensearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:yt='http://gdata.youtube.com/schemas/2007'>
<id>http://gdata.youtube.com/feeds/api/users/id/uploads</id>
<updated>2014-01-07T11:43:08.269Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video'/>
<title type='text'>Uploads by id</title>
<logo>http://www.gstatic.com/youtube/img/logo.png</logo>
<link rel='related' type='application/atom+xml' href='https://gdata.youtube.com/feeds/api/users/stonemarketuk'/>
<link rel='alternate' type='text/html' href='https://www.youtube.com/channel/333/videos'/>
<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://gdata.youtube.com/feeds/api/users/id/uploads'/>
<link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml' href='https://gdata.youtube.com/feeds/api/users/id/uploads/batch'/>
<link rel='self' type='application/atom+xml' href='https://gdata.youtube.com/feeds/api/users/id/uploads?start-index=1&max-results=25'/>
<link rel='next' type='application/atom+xml' href='https://gdata.youtube.com/feeds/api/users/id/uploads?start-index=26&max-results=25'/>
<author>
<name>StonemarketUK</name>
<uri>https://gdata.youtube.com/feeds/api/users/id</uri>
</author>
<generator version='2.1' uri='http://gdata.youtube.com'>YouTube data API</generator>
<openSearch:totalResults>30</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>25</openSearch:itemsPerPage>
<entry>
....entry elements
</entry>
<entry>
....entry elements
</entry>
</feed>
How do I get the entry elements? I have tried the following:
var entries = element.Elements("entry");
var entries = element.Element("feed").Elements("entry");
var entries = element.Nodes().Elements("entry");
But none of these return anything
I also debugged and tried element.Elements().FirstOrDefault() but this returned null. element.Nodes().Count() returned 41 so should I be trying to get the nodes called entry?
All elements are in a namespace (xmlns='http://www.w3.org/2005/Atom'). You must declare the atom namespace and use it.
It's easy:
XNamespace atom = "http://www.w3.org/2005/Atom";
var xml = XElement.Load(url);
var entry = xml.Elements(atom + "entry");
etc.
An easy way to get the right Element name is using XName.Get(). If you only have one namespace, you could put it in a seperate function:
internal static XName GetXName(string name)
{
string atomNamespace = "http://www.w3.org/2005/Atom";
return XName.Get(name, atomNamespace);
}
Try the following
var entryList = element.Elements().Where(x => x.Name.LocalName == "entry");
The problem here is that every element without an explicit namespace is implicitly in the namespace "http://www.w3.org/2005/Atom". The LocalName property can still be used to access the simple name as shown above. Barring that you need to construct a proper XName element which includes this namespace in order to match the 'entry' nodes
Related
I have this result from an httpGet and i want to extract some values from it.
<?xml version="1.0" encoding="UTF-8"?>
<ns4:endpoint xmlns:ns4="identity.ers.ise.cisco.com" xmlns:ers="ers.ise.cisco.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema" description="Beskriv" id="eed9d9a0-5c8d-11ea-8778-
9e4294fe2fb6" name="1A:1A:1A:1A:1A:1A">
<link rel="self" href="https://10.100.10.10:9060/ers/config/endpoint/eed9d9a0-5c8d-11ea-8778-
9e4294fe2fb6" type="application/xml" />
<customAttributes>
<customAttributes>
<entry>
<key>Changed By API</key>
<value />
</entry>
<entry>
<key>TAG name</key>
<value>TagNavn</value>
</entry>
<entry>
<key>API Change Date</key>
<value>2020-03-02</value>
</entry>
<entry>
<key>API Changed By</key>
<value>Mot</value>
</entry>
</customAttributes>
</customAttributes>
<groupId>aa13bb40-8bff-11e6-996c-525400b48521</groupId>
<identityStore />
<identityStoreId />
<mac>1A:1A:1A:1A:1A:1A</mac>
<portalUser />
<profileId />
<staticGroupAssignment>true</staticGroupAssignment>
<staticProfileAssignment>false</staticProfileAssignment>
</ns4:endpoint>
I can extract the "name" and "description" by using xmlnode.value, but im not sure how to access my custom attributes such as <mac> and <groupid>
Are they regarded as child nodes?
Any help is appreciated.
Something as simple as (using XDocument class from System.Xml.Linq namespace):
// You don't need below line
// XDocument xml = XDocument.Load(#"path to txt file");
var macElement = xml.Descendants().Where(element => element.Name == "mac").FirstOrDefault();
// Similairly for groupid elemnt
var groupidElement = xml.Descendants().Where(element => element.Name == "groupid").FirstOrDefault();
if(macElement != null)
{
// do something with macElement.Value
}
if(groupidElement != null)
{
// do something with groupidElement.Value
}
Also call to xml.Descendants() is reduntant, so you could store it in variable like:
var descendants = xml.Descendants();
and reuse it.
I am trying get the email value under author node in C#. But nothing is coming. My Code is=
XDocument xDoc = XDocument.Parse("myxml");
var foos = from xelem in xDoc.Descendants("author")
select xelem.Element("email").Value;
XML which i am using is -
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:batch="http://schemas.google.com/gdata/batch"
xmlns:gContact="http://schemas.google.com/contact/2008" xmlns:gd="http://schemas.google.com/g/2005"
xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">
<id>yogeshcp13#gmail.com</id>
<updated>2015-02-09T04:03:31.220Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/contact/2008#contact"/>
<title type="text">Yogesh Adhikari's Contacts</title>
<link rel="alternate" type="text/html" href="https://www.google.com/"/>
<link rel="next" type="application/atom+xml" href="https://www.google.com/m8/feeds/contacts/yogeshcs2003%40gmail.com/full?max-
results=1&start-index=2"/>
<author>
<name>Yogesh Adhikari</name>
<email>yogeshcp13#gmail.com</email>
</author>
<generator version="1.0" uri="http://www.google.com/m8/feeds">Contacts</generator>
<openSearch:totalResults>3099</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>1</openSearch:itemsPerPage>
</feed>
Can someone point out what is wrong?
Thanks
You need to specify the namespace along with the name when getting the descendants.
XDocument xDoc = XDocument.Parse("myxml");
string ns = xDoc.Root.Name.Namespace;
var foos = from xelem in xDoc.Descendants(ns + "author")
select xelem.Element(ns + "email").Value;
Alternatively, you can find your nodes by getting an enumeration over all descendants, then filtering by LocalName. If email is a node only within authors in your schema, you can also avoid the unnecessary step of drilling down from author nodes, and just find your email nodes directly:
var foos = xdoc.Descendants().Where(e => e.Name.LocalName == "email");
XDocument xDoc = XDocument.Load("myxml.xml");
var foos = xDoc.Descendants().Where(e => e.Name.LocalName == "email");
Console.WriteLine(foos.FirstOrDefault().Value);
Use Load method if you are refering to xml file else parse should be fine. Also make sure xml is along with your binaries' folder if not using specific path.
I'm using SharePoint 2013's REST API to get XML to parse, but I'm having trouble parsing a certain chunk of XML. Here's a truncated example of some XML I might get back that I have no problem parsing:
<feed xml:base="http://server/DesktopApplications/_api/" 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" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
<id>2dff4586-6b7d-4186-ae63-4d048f74a112</id>
<title />
<updated>2014-03-19T15:32:15Z</updated>
<entry m:etag=""19"">
<id>http://server/DesktopApplications/_api/Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')</id>
<category term="SP.List" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')" />
<title />
<updated>2014-03-19T15:32:15Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:BaseTemplate m:type="Edm.Int32">101</d:BaseTemplate>
<d:BaseType m:type="Edm.Int32">1</d:BaseType>
<d:Id m:type="Edm.Guid">0ac46109-38d9-4070-96b7-f90085b56f1e</d:Id>
<d:ListItemEntityTypeFullName>SP.Data.Shared_x0020_DocumentsItem</d:ListItemEntityTypeFullName>
<d:Title>Documents</d:Title>
</m:properties>
</content>
</entry>
...
</feed>
I can parse this just fine using XDocument with the following:
private static readonly XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
private static readonly XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
...
List<KLList> lists = doc.Descendants(m + "properties").Select(
list => new KLList()
{
Id = list.Element(d + "Id").Value,
Title = list.Element(d + "Title").Value,
ListItemEntityTypeFullName = list.Element(d + "ListItemEntityTypeFullName").Value,
BaseType = (BaseType)Convert.ToInt32(list.Element(d + "BaseType").Value),
ListTemplateType = (ListTemplateType)Convert.ToInt32(list.Element(d + "BaseTemplate").Value)
}).ToList();
When I expand my query to get the server relative url of the list's root folder, I get XML like this that I have trouble with:
<feed xml:base="http://server/DesktopApplications/_api/" 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" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
<id>a01c22dc-a87f-4253-91d1-0a6ef8efa6d0</id>
<title />
<updated>2014-03-19T15:27:11Z</updated>
<entry m:etag=""19"">
<id>http://server/DesktopApplications/_api/Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')</id>
<category term="SP.List" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RootFolder" type="application/atom+xml;type=entry" title="RootFolder" href="Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')/RootFolder">
<m:inline>
<entry>
<id>http://server/DesktopApplications/_api/Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')/RootFolder</id>
<category term="SP.Folder" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')/RootFolder" />
<title />
<updated>2014-03-19T15:27:11Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:ServerRelativeUrl>/DesktopApplications/Shared Documents</d:ServerRelativeUrl>
</m:properties>
</content>
</entry>
</m:inline>
</link>
<title />
<updated>2014-03-19T15:27:11Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:BaseTemplate m:type="Edm.Int32">101</d:BaseTemplate>
<d:BaseType m:type="Edm.Int32">1</d:BaseType>
<d:Id m:type="Edm.Guid">0ac46109-38d9-4070-96b7-f90085b56f1e</d:Id>
<d:ListItemEntityTypeFullName>SP.Data.Shared_x0020_DocumentsItem</d:ListItemEntityTypeFullName>
<d:Title>Documents</d:Title>
</m:properties>
</content>
</entry>
...
</feed>
I tried using basically the same code because I want the ServerRelativeUrl to be on the same object:
List<KLList> lists = doc.Descendants(m + "properties").Select(
list => new KLList()
{
Id = list.Element(d + "Id").Value,
Title = list.Element(d + "Title").Value,
ListItemEntityTypeFullName = list.Element(d + "ListItemEntityTypeFullName").Value,
BaseType = (BaseType)Convert.ToInt32(list.Element(d + "BaseType").Value),
ListTemplateType = (ListTemplateType)Convert.ToInt32(list.Element(d + "BaseTemplate").Value),
RelativeUrl = list.Element(d + "ServerRelativeUrl").Value
}).ToList();
But this no longer works. The first thing doc.Descendants(m + "properties") returns is
<m:properties>
<d:ServerRelativeUrl>/DesktopApplications/Shared Documents</d:ServerRelativeUrl>
</m:properties>
so trying to set the other properties at the same time throws an object reference exception, because the other elements aren't here.
How can I parse this XML so that all of the values I want go into one object? I'd rather not have to make a separate call to get the root folder url for each list.
Update:
I posted an answer below, but I feel like there is a better way out there somewhere. Feel free to post an answer if it's better than mine and I'll mark yours as the answer.
I figured out a way to get me what I need but I feel like there has to be a better way...
private readonly XNamespace a = "http://www.w3.org/2005/Atom";
private readonly XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
private readonly XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
List<KLList> lists = doc.Descendants(a + "entry").Where(element => element.Attribute(m + "etag") != null).Select(
list => new KLList()
{
Id = list.Descendants(d + "Id").FirstOrDefault().Value,
Title = list.Descendants(d + "Title").FirstOrDefault().Value,
ListItemEntityTypeFullName = list.Descendants(d + "ListItemEntityTypeFullName").FirstOrDefault().Value,
BaseType = (BaseType)Convert.ToInt32(list.Descendants(d + "BaseType").FirstOrDefault().Value),
ListTemplateType = (ListTemplateType)Convert.ToInt32(list.Descendants(d + "BaseTemplate").FirstOrDefault().Value),
RelativeUrl = list.Descendants(d + "ServerRelativeUrl").FirstOrDefault().Value
}).ToList();
What you want to do is to check that the element exists before getting it's value because at the moment you are just assuming that they will always exist.
This has been asked before here (I haven't got enough reputation to post this as a comment):
Check if an element exists when parsing XML
I have a XML file:
<SourceMessage xmlns="test.test">
<updated>2011</updated>
<title type="p1"/>
<title type="p2"/>
<title type="p3"/>
<entry>
</entry>
</SourceMessage>
How could I use LINQ to get the <type> attribute of the <title> element, i.e. "p1", "p2" and "p3"?
Use XDocument.Load or XDocument.Parse to load the XML data into an XDocument. Then, using LINQ, you can get the type for each <title> element under the document root as follows:
XNamespace test = "test.test";
XDocument doc = XDocument.Load(file);
// - or -
XDocument doc = XDocument.Parse("<SourceMessage ...");
IEnumerable<string> query = from title in doc.Root.Elements(test + "title")
select (string)title.Attribute("type");
foreach (string item in query)
{
Console.WriteLine(item);
}
Output:
p1
p2
p3
var xElement XElement.Parse(xmlString);
var result = xElement.Descendants("title")
.Select(e => e.Attribute("type").Value);
XDocument xml = XDocument.Parse (#"<SourceMessage xmlns="test.test">
<updated>2011</updated>
<title type="p1"/>
<title type="p2"/>
<title type="p3"/>
<entry>
</entry>
</SourceMessage>");
foreach (var t in xml.Root.Descendants("title"))
Console.Write(t.Attribute("type").Value);
So, in the XML below using this code sample, i can successfully grab HomeAddress and Name information for each entry from my XML. What if I also need to grab the ID (drivers license numberxxx) information from each entry?
EDIT: Updated XML sample for clarificaiton
Code Sample:
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(responseFromServer);
XmlNamespaceManager xnsmgr = new XmlNamespaceManager(xDoc.NameTable);
xnsmgr.AddNamespace("ns1", "http://www.w3.org/2005/Atom");
xnsmgr.AddNamespace("ns2", "http://strange.com/ns/1.0/");
XmlNodeList xnlInsuredListMembers = xDoc.SelectNodes("//ns2:InsuredListMember", xnsmgr);
foreach (XmlNode xnMember in xnlInsuredListMembers)
{
XmlNode xnHomeAddress = xnMember.SelectSingleNode("ns2:HomeAddress", xnsmgr);
string sHomeAddress = xnHomeAddress.InnerText;
XmlNode xnName = xnMember.SelectSingleNode("ns2:Name", xnsmgr);
string sName = xnName.InnerText;
MessageBox.Show(sHomeAddress + sName);
}
XML Sample
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>someID</id>
<title type="text">Title</title>
<author>
<name>XML Author</name>
</author>
<updated>2010-10-25T20:05:30.267Z</updated>
<link href="currentURL"></link>
<link href="nextURL"></link>
<entry>
<id>Drivers License Numberxxx</id>
<content type="application/vnd.ctct+xml">
<InsuredListMember xmlns="http://strange.com/ns/1.0/">
<HomeAddress>123 anystreet</HomeAddress>
<Name>doe, somegal</Name>
</InsuredListMember>
</content>
</entry>
<entry>
<id>Drivers License Numberxxx</id>
<content type="application/vnd.ctct+xml">
<InsuredListMember xmlns="http://strange.com/ns/1.0/">
<HomeAddress>321 anystreet</HomeAddress>
<Name>doe, someguy</Name>
</InsuredListMember>
</content>
</entry>
</feed>
First, this //ns2:ContactListMember should be //ns2:InsuredListMember according to your input sample.
Second, if the context node is some ns2:InsuredListMember, the the id attribute is selected by this expresion: #id.
If you want the ns1:id child of ns1:entry for the given ns2:InsuredListMember, this XPath expression: ../../ns1:id