I cannot access XML data using LINQ to XML from a file - c#

I have the following XML in a file called contents.xml that is in the data directory in my C drive:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="http://datacenter1.table.core.windows.net/"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://www.w3.org/2005/Atom">
<title type="text">TestContents</title>
<entry>
<title type="text" />
<author>
<name />
</author>
<link rel="edit" title="TestContents" />
<content type="application/xml">
<m:properties>
<d:PartitionKey>0100000</d:PartitionKey>
<d:Text>xx</d:Text>
</m:properties>
</content>
</entry>
<entry>
<title type="text" />
<updated />
I need to get the values of the <d:Text> so I created this console application:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
XDocument xmlDoc = XDocument.Load(#"c:\data\contents.xml");
var q = from c in xmlDoc.Descendants("entry")
select (string)c.Element("link") ;
Console.WriteLine(q);
}
}
}
But I have two problems. Firstly the console shows but then disappears before I can see the output. Second if I look at q in the debugger it says "enumeration returns no results".
What's the best way that I can use to get what I really need which is the values of the many <d:Text> ?

First Problem: After Console.WriteLine(q) line, you can write Console.ReadLine(). So result will be displayed until you press "Enter".
Second Problem: If you want all values in a list then u can do q.ToList()

Related

Iterating through linq results results in more items than query count

I'm fairly new to LINQ but this seemed pretty straightforward.
I have an XML doc which contains a structure like this:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<folders>
<folder id="-1" parent="-100">
<name><![CDATA[Root]]></name>
<children>
<folder id="2" parent="-1">
<name><![CDATA[Contribution]]></name>
<documents />
<children>
<folder id="775" parent="2">
<name><![CDATA[category1]]></name>
<documents />
<children>
<folder id="2319" parent="775">
<name><![CDATA[Acad_Depts1]]></name>
<documents />
<children>
<folder id="26965" parent="2319">
<name><![CDATA[Student1]]></name>
<documents>
<document>
</document>
</documents>
</folder
</children>
</folder>
<folder id="2319" parent="775">
<name><![CDATA[Acad_Depts2]]></name>
<documents />
<children>
<folder id="26965" parent="2319">
<name><![CDATA[Student1]]></name>
<documents>
<document>
</document>
</documents>
</folder
</children>
</folder>
etc...
</children>
</folder>
</children>
</folder>
</children>
</folder>
</folders>
What I'm trying to do is to select all the elements with an attribute 'parent="775"'.
XElement xelement = XElement.Load("folders_only_registrar_folder.xml");
IEnumerable <XElement> folders = xelement.Elements();
var query = from node in folders.Descendants("folder")
where node.Attribute("parent").Value == registrarNodeID
select node;
Console.WriteLine(query.Count());
Console.ReadKey();
foreach(XElement departmentNode in query.Descendants("name"))
{
Console.WriteLine(departmentNode.Value.ToString());
}
When I run the query and test the count, I get 48 results (which is good)... but when I try to write out those same nodes, I get hundreds of results. For some reason it's giving me almost ALL of the elements named "folder" including children folders.
Thoughts as to what I'm doing wrong?
UPDATE... ok so now I know why i'm getting all the folders but any thoughts on how to create a collection of each grouping of nodes and sub-nodes?
Can the selection in LINQ send each 775 folder node (plus it's collective sub-nodes) into some sort of collection of nodes and then I could parse through them in a foreach by grouping of node?
Replace query.Descendants() with just query. query.Descendants() gets every child of every node that was originally contained within query.

Rest/Odata $Filter not working on certain keys

I am trying to query some information from a SharePoint list. Now, I am trying to use odata to get it. my problem is that for some reason, $filter is not working with all my keys in that list :S. Here is an example:
This works OK:
...ccm/_api/Lists/GetByTitle('Circuit%20Deliveries')/Items?$filter=Title eq 'AUG'
But this one doesn't work (HTTP 400 bad request)
...ccm/_api/Lists/GetByTitle('Circuit%20Deliveries')/Items?$filter=Delivery_x0020_Date eq null
Nevertheless, the field name is OK, since I am able to use select and orderby with the same field name. Here is the XML output in IE for 2 'Titles' named AUG:
...ccm/_api/Lists/GetByTitle('Circuit%20Deliveries')/Items?$filter=Title
eq
'AUG'&$select=Title,Delivery_x0020_Date,Status_x0020__x002d__x0020_Calcu
<?xml version="1.0" encoding="utf-8" ?> -
<feed xml:base="/ccm/_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>5a2630a8-c00a-4baa-bd43-3912d9264df8</id>
<title />
<updated>2017-09-08T10:58:12Z</updated>
<entry m:etag="" 33 "">
<id>Web/Lists(guid'5ad8ca39-191a-4586-bdef-7bc4830eced9')/Items(332)</id>
<category term="SP.Data.Circuit_x0020_DeliveriesListItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'5ad8ca39-191a-4586-bdef-7bc4830eced9')/Items(332)" />
<title />
<updated>2017-09-08T10:58:12Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:Title>AUG</d:Title>
<d:Delivery_x0020_Date m:type="Edm.DateTime">2017-03-06T06:00:00Z</d:Delivery_x0020_Date>
<d:Status_x0020__x002d__x0020_Calcu>Circuit Ready for Production Use on 03/06/2017</d:Status_x0020__x002d__x0020_Calcu>
</m:properties>
</content>
</entry>
<entry m:etag="" 58 "">
<id>Web/Lists(guid'5ad8ca39-191a-4586-bdef-7bc4830eced9')/Items(333)</id>
<category term="SP.Data.Circuit_x0020_DeliveriesListItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'5ad8ca39-191a-4586-bdef-7bc4830eced9')/Items(333)" />
<title />
<updated>2017-09-08T10:58:12Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:Title>AUG</d:Title>
<d:Delivery_x0020_Date m:null="true" />
<d:Status_x0020__x002d__x0020_Calcu>Site Survey completed on 09/09/2016</d:Status_x0020__x002d__x0020_Calcu>
</m:properties>
</content>
</entry>
</feed>
As you can see I was able to successfully query and select both fields from the list and filter by Title. Nevertheless, I would like to further filter on Delivery_x0020_Date being empty (or null).
I searched around and some people were saying that filtering by null on dates is not always working. But in my case is a bit more than that, because even if I try to filter by another key(Status_x0020__x002d__x0020_Calcu) it will return Bad Request
Is there a requirement on what type of keys you can filter on?
Thank you
REST API in SharePoint 2013 does Not support null values for filtering on list item queries. (Refer this MSDN link)
You will have to find some other workaround.
however, We can combine the CAML query with REST API to get the required data in Javascript object model. Refer this link - REST API to filter on null.
But I am not sure about the c# code.

How to use LINQ to get data from an XML file?

I have xml files which look like this:
<?xml version="1.0" encoding="utf-8"?>
<record id="177" restricted="false">
<type>record type</type>
<startdate>2000-10-10</startdate>
<enddate>2014-02-01</enddate>
<titles>
<title xml:lang="en" type="main">Main title</title>
<!-- only one title element with type main -->
<title xml:lang="de" type="official">German title</title>
<!-- can have more titles of type official -->
</titles>
<description>description of the record</description>
<categories>
<category id="122">
<name>category name</name>
<description>category description</description>
</category>
<!-- can have more categories -->
</categories>
<tags>
<tag id="5434">
<name>tag name</name>
<description>tag description</description>
</tag>
<!-- can have more tags -->
</tags>
</record>
How do I select the data from these xml files using LINQ, or should I use something else?
You can load xml into XDocument objects using either the Load() method
for files, or the Parse() method for strings:
var doc = XDocument.Load("your-file.xml");
// OR
var doc = XDocument.Parse(yourXmlString);
Then you can access the data using LINQ:
var titles =
from title in doc.XPathSelectElements("//title")
where title.Attribute("type").Value == "official"
select title.Value;
Was searching for examples of Xmlserializer and found this: How to Deserialize XML document
So why not to try. I did Ctrl+C and Edit -> Paste Special -> Paste XML As Classes in Visual Studio 2013 and... Whoa I got all the classes generated. One condition target framework must be 4.5 and this function is available from Visual Studio 2012+ (as stated in that post)

Parsing malformed XML with RestSharp

I have a webservice that I need to consume that's returning the following:
<catalog modules="2" children="0">
<title>Test Catalog</title>
<link type="application/xml" rel="self" href="http://someurl"/>
<link type="text/html" rel="alternate" href="http://someurl"/>
<parent modules="0" children="3">
<title>Top</title>
<link type="application/xml" rel="self" href="http://someurl"/>
<link type="text/html" rel="alternate" href="http://someurl"/>
</parent>
<module>
<id>MODULEID123</id>
<title>Some module title</title>
<link type="application/xml" rel="self" href="http://someurl"/>
<link type="text/html" rel="alternate" href="http://someurl"/>
<type>type123</type>
<description>Some Description</description>
</module>
<module>
<id>MODULEID456</id>
<title>Some other module title</title>
<link type="application/xml" rel="self" href="http://someurl"/>
<link type="text/html" rel="alternate" href="http://someurl"/>
<type>type123</type>
<description/>
</module>
</catalog>
I'm using RestSharp to consume the service, and under normal circumstances I'd expect the tags to be underneath a parent node or something similar so that I could just a response class with a List<Module> Modules that would just automatically pull them in. However, since they're just out there equal to the <parent>, <title> and <link> nodes, it looks almost malformed (though, admittedly, it's been a long time since I've been deep into how XML *should * look - thank you, JSON!
So, given that this is the returned result, how can I direct RestSharp to parse this? If RestSharp expects well formed XML, and thus rejects this, should I just manually parse this using an XMLReader the old fashioned way?
Oops, found it in the documentation. Evidently this is convention-based, so while this looks a bit wonky, it should be no problem if I just assume there's a parent there build my response class correctly.
From the docs...
XmlDeserializer
Two different types of lists are handled: parentless (inline) and regular (nested). For instance, both of the following XML structures
<?xml version="1.0" encoding="utf-8" ?>
<InlineListSample>
<image src="1.gif">value1</image>
<image src="2.gif">value2</image>
<image src="3.gif">value3</image>
<image src="4.gif">value4</image>
</InlineListSample>
<?xml version="1.0" encoding="utf-8" ?>
<NestedListSample>
<images>
<image src="1.gif">value1</image>
<image src="2.gif">value2</image>
<image src="3.gif">value3</image>
<image src="4.gif">value4</image>
</images>
</NestedListSample>
Will map to the following C# schema:
public class ListSample
{
public List<Image> Images { get; set; }
}
public class Image
{
public string Src { get; set; }
public string Value { get; set; }
}
If by chance both element structures existed in the same document at the relevant point in the hierarchy, parented/nested/regular lists take priority.

Reading different XML with C#/DOM

I am currently using DOM to navigate xml in my C# project. However, some XML that i've come across lately is a bit different.
whereas usually I have:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<entry>
<author>
<name>Me =)</name>
</author>
<content>
<somefield1>
<Subfield>subfield data</subfield>
</somefield>
</content>
</entry>
</feed>
and can navigate using foreach entry as entry, selectsinglenode(/content/somefield1/subfield), innertext to get the data from the subfield for each entry, the new XML looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
<atom:entry>
<atom:author>
<name>Me =)</name>
</atom:author>
<atom:content>
<somefield1>
<Subfield>subfield data</subfield>
</somefield>
</atom:content>
</atom:entry>
</atom:feed>
selectsinglenode(/atom:content/somefield1/subfield) is definitely not going to work...any suggestions?
atom: is just the namespace, and possibly you might just ignore it. If it still not works, you may have to use:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom");
selectsinglenode("atom:content/somefield1/subfield", nsmgr);
Which is documented here

Categories

Resources