Convert XML to a list of something - c#

I have a xml file coming from my php site as an api.
This is the xml that is coming back from my php application.
<xml>
<overzicht>
<item>
<sessieID>6</sessieID>
<onderwerp>Vrijwilligers, een uitstervend rasnn</onderwerp>
<omschrijving>Ode aan de vrijwilligers jjj</omschrijving>
<sprekerID>1</sprekerID>
<lokaalID>20</lokaalID>
<themaID>1</themaID>
<typeID>2</typeID>
<periodeID>2</periodeID>
<datum>2012-02-20</datum>
<maximaleInschrijvingen>1</maximaleInschrijvingen>
<spreker>
<sprekerID>1</sprekerID>
<sprekerNaam>Rik Torfs</sprekerNaam>
<loginID>13</loginID>
</spreker>
<lokaal>
<lokaalID>20</lokaalID>
<campusNaam>Malle</campusNaam>
<lokaalOpCampus>W10</lokaalOpCampus>
<typeID>2</typeID>
</lokaal>
</item>
<item>
<sessieID>15</sessieID>
<onderwerp>VPKB</onderwerp>
<omschrijving/>
<sprekerID>6</sprekerID>
<lokaalID>2</lokaalID>
<themaID>1</themaID>
<typeID>1</typeID>
<periodeID>2</periodeID>
<datum>2012-02-20</datum>
<maximaleInschrijvingen>50</maximaleInschrijvingen>
<spreker>
<sprekerID>6</sprekerID>
<sprekerNaam>Dick Wursten</sprekerNaam>
<loginID>18</loginID>
</spreker>
<lokaal>
<lokaalID>2</lokaalID>
<campusNaam>KHK Vorselaar</campusNaam>
<lokaalOpCampus>A102</lokaalOpCampus>
<typeID>1</typeID>
</lokaal>
</item>
...
</overzicht>
</xml>
This is my C# code. I want to get al list of Sessie.
XDocument xmlDoc = XDocument.Parse(e.Result);
List<Sessie> sessies =
(
from item in xmlDoc.Descendants("overzicht")
select new Sessie(
item.Element("onderwerp").Value,
Convert.ToInt32(item.Element("sessieID").Value),
item.Element("omschrijving").Value,
(Spreker)(
new Spreker(
Convert.ToInt32(item.Element("spreker").Element("sprekerID").Value),
item.Element("spreker").Element("sprekernaam").Value)
),
Convert.ToDateTime(item.Element("datum").Value),
Convert.ToInt32(item.Element("maximaleInschrijvingen").Value),
(Lokaal)(
new Lokaal(
Convert.ToInt32(item.Element("lokaal").Element("lokaalID").Value),
item.Element("lokaal").Element("campusNaam").Value,
item.Element("lokaal").Element("lokaalOpCampus").Value)
)
)
).ToList<Sessie>();
I know my code isn't working with this exception.
"NullReferenceException"

There's one fairly obvious problem to start with. Look at the very start of your query:
from item in xmlDoc.Descendants("overzicht")
select new Sessie(item.Element("onderwerp").Value,
...
That will only work if there's an <onderwerp> directly under <overzicht>. There isn't - it's under the <item> element. Perhaps (given the range variable name) you meant:
from item in xmlDoc.Descendants("item")
select new Sessie(item.Element("onderwerp").Value,
...

The query
from item in xmlDoc.Descendants("overzicht")
will return a list of <overzicht> elements. item.Element("onderwerp") does not exist, you are missing the <item> element in between.
Simple fix:
from item in xmlDoc.Descendants("item")

Related

How to get enclosure url with XElement C# Console

I read multiple feed from many sources with C# Console, and i have this code where i load XML From sources:
XmlDocument doc = new XmlDocument();
doc.Load(sourceURLX);
XElement xdoc = XElement.Load(sourceURLX);
How to get enclosure url and show as variable?
If I understand your question correctly (I'm making a big assumption here) - you want to select an attribute from the root (or 'enclosing') tag, named 'url'?
You can make use of XPath queries here. Consider the following XML:
<?xml version="1.0" encoding="utf-8"?>
<root url='google.com'>
<inner />
</root>
You could use the following code to retrieve 'google.com':
String query = "/root[1]/#url";
XmlDocument doc = new XmlDocument();
doc.Load(sourceURLX);
String value = doc.SelectSingleNode(query).InnerText;
Further information about XPath syntax can be found here.
Edit: As you stated in your comment, you are working with the following XML:
<item>
<description>
</description>
<enclosure url="blablabla.com/img.jpg" />
</item>
Therefore, you can retrieve the url using the following XPath query:
/item[1]/enclosure[1]/#url
With xml like below
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>title</title>
<link>https://www.link.com</link>
<description>description</description>
<item>
<title>RSS</title>
<link>https://www.link.com/xml/xml_rss.asp</link>
<description>description</description>
<enclosure url="https://www.link.com/media/test.wmv"
length="10000"
type="video/wmv"/>
</item>
</channel>
</rss>
You will get url by reading attribute
var document = XDocument.Load(sourceURLX);
var url = document.Root
.Element("channel")
.Element("item")
.Element("enclosure")
.Attribute("url")
.Value;
To get multiple urls
var urls = document.Descendants("item")
.Select(item => item.Element("enclosure").Attribute("url").Value)
.ToList();
Using foreach loop
foreach (var item in document.Descendants("item"))
{
var title = item.Element("title").Value;
var link = item.Element("link").Value;
var description = item.Element("description").Value;
var url = item.Element("enclosure").Attribute("url").Value;
// save values to database
}

How to correctly perform Linq-to-XML query?

I have a XDocument called currentIndex like that:
<INDEX>
<SUBINDEX>
<!-- Many tag and infos -->
<SUBINDEX>
<ITEM>
<IDITEM>1</IDITEM>
<ITEM>
<ITEM>
<IDITEM>2</IDITEM>
<ITEM>
...
<ITEM>
<IDITEM>n</IDITEM>
<ITEM>
</INDEX>
I would recreate a new XDocument similar to above one:
<INDEX>
<SUBINDEX>
<!-- Many tag and infos -->
<SUBINDEX>
<ITEM>
<IDITEM>2</IDITEM>
<ITEM>
</INDEX>
I want to do this in C#, I have tried starting in this way:
public void ParseItems(XDocument items)
{
IEnumerable<XElement> items = from a in indexGenerale.Descendants(XName.Get("ITEM"))
// where a.Element("IDITEM").Equals("2")
select a;
foreach(var item in items) {
// do something
}
}
Now the problem: If where clause is commented, items contains n elements (one for each ITEM tag), but if I remove that comments items is empty. Why this behaviour. How I need to perform a search?
Use an explicit cast:
from a in indexGenerale.Descendants("ITEM")
where (string)a.Element("IDITEM") == "2"
a.Element("IDITEM") will return an XElement and it will never be equal to "2".Maybe you meant a.Element("IDITEM").Value.Equals("2"), that will also work but explicit cast is safer.It doesn't throw exception if the element wasn't found`,

JsonConvert.DeserializeXmlNode - must begin with an object

I'm getting a JsonSerializationException calling DeserializeXmlNode() on JSON data that starts with [[ (i.e. it's an array of arrays).
What is the best
way to turn this into XML?
Are there any other JSON schemas that can't be turned into XML?
Update: How the XML should appear is an interesting question. Having an array of arrays means there is no root node (that's an easy one - insert ) but also the set of children nodes have no name. I'm not sure what makes sense here. And this may be a deal killer for using XPath on JSON. So on this part too, any suggestions?
Update 2 - the JSON data:
[["P0010001","NAME","state"],
["4779736","Alabama","01"],
["710231","Alaska","02"],
["6392017","Arizona","04"],
["2915918","Arkansas","05"],
["37253956","California","06"],
["5029196","Colorado","08"],
["3574097","Connecticut","09"],
["897934","Delaware","10"],
["601723","District of Columbia","11"],
["18801310","Florida","12"],
["9687653","Georgia","13"],
["1360301","Hawaii","15"],
["1567582","Idaho","16"],
["12830632","Illinois","17"],
["6483802","Indiana","18"],
["3046355","Iowa","19"],
["2853118","Kansas","20"],
["4339367","Kentucky","21"],
["4533372","Louisiana","22"],
["1328361","Maine","23"],
["5773552","Maryland","24"],
["6547629","Massachusetts","25"],
["9883640","Michigan","26"],
["5303925","Minnesota","27"],
["2967297","Mississippi","28"],
["5988927","Missouri","29"],
["989415","Montana","30"],
["1826341","Nebraska","31"],
["2700551","Nevada","32"],
["1316470","New Hampshire","33"],
["8791894","New Jersey","34"],
["2059179","New Mexico","35"],
["19378102","New York","36"],
["9535483","North Carolina","37"],
["672591","North Dakota","38"],
["11536504","Ohio","39"],
["3751351","Oklahoma","40"],
["3831074","Oregon","41"],
["12702379","Pennsylvania","42"],
["1052567","Rhode Island","44"],
["4625364","South Carolina","45"],
["814180","South Dakota","46"],
["6346105","Tennessee","47"],
["25145561","Texas","48"],
["2763885","Utah","49"],
["625741","Vermont","50"],
["8001024","Virginia","51"],
["6724540","Washington","53"],
["1852994","West Virginia","54"],
["5686986","Wisconsin","55"],
["563626","Wyoming","56"],
["3725789","Puerto Rico","72"]]
I had an array of objects, shaped like:
[{foo:bar}, {foo:bar2}]
...What I did to work around this problem is to wrap the text first like so:
public XmlDocument JsonArrayToXml(string json)
{
var wrappedDocument = string.Format("{{ item: {0} }}", json);
var xDocument = JsonConvert.DeserializeXmlNode(wrappedDocument, "collection");
return xDocument;
}
This does not throw an error. The shape of the XML resembles:
<?xml version="1.0" encoding="UTF-8"?>
<collection>
<item>
<foo>bar</foo>
</item>
<item>
<foo>bar2</foo>
</item>
</collection>

When parsing XML with Linq, only one object gets fetched

I'm trying to populate an array with the following xml:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<data>
<item>
<date>1307018090</date>
<price>10.4718867</price>
<low>10.38100000</low>
<high>10.49000000</high>
<nicedate>14:39</nicedate>
</item>
<item>
...
</item>
and so on
I'm using this Linq-query, which to me means that It'll create one object per :
var items = from item in doc.Element("data").Descendants()
select new Currency
{
Close = item.Element("price").Value.ToString(),
Date = item.Element("date").Value.ToString(),
Low = item.Element("low").Value.ToString(),
High = item.Element("high").Value.ToString(),
Time = item.Element("nicedate").Value.ToString()
};
And when I foreach through items, only one item gets selected. I'm not very used to Linq so I can't figure out how to properly construct this statement. Any suggestions?
You need to start the Linq-Xml like so
var items =
from item in
doc.Element("data")
.Elements("item")
Descedants() method returns not only children, but also grand-children, grand-grand-children etc. So, the second tag that gets processed by LINQ is your first <item>'s <date> and it isn't processed (I think there should be an exception here, can't check at the moment).
Replace your Descedants() call to Elements("item"), as suggested by #DaveShaw

Linq to XML, extracting attributes and elements

I am new to XML and Linq to XML and I just can't find a good guide that explains how to work with it. I have a simple XML string structured as follows
<mainitem>
<items>
<itemdescription>ABC</itemdescription>
<item>
<itemtext>XXX</itemtext>
</item>
<item>
<itemtext>YYY</itemtext>
</item>
<item>
<itemtext>ZZZ</itemtext>
</item>
</items>
<overalldescription>ABCDEFG</overalldescription>
<itemnodes>
<node caption="XXX" image="XXX"></node>
<node caption="YYY" image="YYY"></node>
<node caption="ZZZ" image="ZZZ"></node>
</itemnodes>
</mainitem>
I am using C# code like
var Items = (from xElem in XMLCODEABOVE.Descendants("item")
select new ItemObject
{
ItemObjectStringProperty = xElem.Element("itemtext").Value,
}
);
to extract a list of the itemtext objects for use with my code. Where I need help is in extracting a list of the caption and image attributes of my node elements. I also need the overalldescription and the itemdescription. I have tried every variation of the above code substituting Descendant for Elements, Element for Attribute etc. I know this is probably a basic question but there doesn't seem to be a straight forward guide out there to explain this to a beginner.
To get the captions
// IEnumerable<string>
var captions = from node in doc.Descendants("node")
select node.Attribute("caption").Value;
Or both the captions and image attributes in one shot:
// IEnumerable of the anonymous type
var captions = from node in doc.Descendants("node")
select new {
caption = node.Attribute("caption").Value,
image = node.Attribute("image").Value
};
For the descriptions:
// null ref risk if element doesn't exist
var itemDesc = doc.Descendants("itemdescription").FirstOrDefault().Value;
var overallDesc = doc.Descendants("overalldescription ").FirstOrDefault().Value;

Categories

Resources