I am trying to filter out one xml document using xpath and count number of nodes which contain given string.
here is my code
string ElementValue = Action
nodeList = root.SelectNodes(#"/moviedb/movie[contains(genres, "+ ElementValue +")]");
return nodeList.Count;
and part of XML
<moviedb>
<movie>
<imdbid>tt2226321</imdbid>
<genres>Thriller</genres>
<languages>English</languages>
<country>USA</country>
<rating>8</rating>
<runtime>155</runtime>
<title>The Dark Knight</title>
<year>2014</year>
</movie>
<movie>
<imdbid>tt1959490</imdbid>
<genres>Action,Adventure,Drama</genres>
<languages>English</languages>
<country>USA</country>
<rating>6.5</rating>
<runtime>138</runtime>
<title>Noah</title>
<year>2014</year>
</movie>
</moviedb>
I guess that it is something with xpath contains expression. While i was using full match syntax, everything was working correctly.
thanks again
Use single-quotes in your XPath whenever possible to make your life easier :
nodeList = root.SelectNodes(#"/moviedb/movie[contains(genres, '"+ ElementValue +"')]");
Or you can use String.Format() method to concatenate values from variables into single string result in a more intuitive way (especially when you have many variables to be "injected" to the string) :
var xpath = String.Format("/moviedb/movie[contains(genres, '{0}')]", ElementValue);
nodeList = root.SelectNodes(xpath);
This is the sample xml of a feed item
<item>
<pubDate>2013-12-11 10:28:55</pubDate>
<title>
SAG Awards Nominations: 12 Years a Slave, Breaking Bad lead the race
</title>
<link>
http://www.rottentomatoes.com/m/1929182/news/1929182/
</link>
<description>
<![CDATA[ ]]>
</description>
<atom:link rel="thumbnail" type="image/*" href="http://content6.flixster.com/movie/11/17/36/11173600_tmb.jpg"/>
</item>
c# code for parsing xml elements
List<XElement> elementsList = xmlItems.Descendants("item").ToList();
foreach (XElement rssItem in elementsList)
{
RSSItem rss = new RSSItem();
rss.Description1 = rssItem.Element("description").Value;
rss.Link1 = rssItem.Element("link").Value;
rss.Title1 = rssItem.Element("title").Value;
rss.ImageUrl= ;
}
I successfully parsed the xml elements except the atom:link tag url.
How we can parse the href property from the atom:link tag ?
Link has a namespace, you need to indicate it when parsing the XML. I don't remember exactly what namespace atom is, but it should be indicated somewhere in the XML file (usually on the root node). For instance, if it is:
<feed xmlns:atom="http://www.w3.org/2005/Atom">
Then you need to parse it like this:
rss.Link1 = (string)rssItem.Element(XName.Get("link", "http://www.w3.org/2005/Atom")).Attribute("href");
You need to specify the namespace when you look for the element:
XNamespace atom = "http://www.w3.org/2005/Atom";
...
rss.Link1 = rssItem.Element(atom + "link").Attribute("href").Value;
LINQ to XML makes namespace handling much simpler than any other XML API I've seen, but you still need to be aware of it. (I'm surprised the other elements aren't in a namespace, to be honest.)
I'd also transform your foreach loop into a LINQ query:
var items = xmlItems.Descendants("item")
.Select(x => new RSSItem {
Description1 = x.Element("description").Value,
Link1 = x.Element(atom + "link").Attribute("href").Value,
Title1 = x.Element("title").Value,
...
})
.ToList();
Also consider using a cast to string instead of the Value property, if some of the elements may be missing - that will set the relevant property to null, instead of throwing a NullReferenceException.
EDIT: If the link element is missing, you can fix that with:
Link1 = (string) x.Elements(atom + "link").Attributes("href").FirstOrDefault()
That will find the first href attribute within an atom link element, or use null - and then the cast to string will just return null if there's no attribute. (That's part of the user-defined conversion from XAttribute to string.)
I have an xml file loaded into an XDocument that I need to extract a value from, and I'm not sure of the best way to do it. Most of the things I'm coming up with seem to be overkill or don't make good use of xml rules. I have the following snippet of xml:
<entry>
<observation classCode="OBS" moodCode="EVN">
<templateId root="2.16.840.1.113883.10.20.6.2.12" />
<code code="121070" codeSystem="1.2.840.10008.2.16.4" codeSystemName="DCM" displayName="Findings">
</code>
<value xsi:type="ED">
<reference value="#121071">
</reference>
</value>
</observation>
</entry>
There can be any number of <entry> nodes, and they will all follow a similar pattern. The value under the root attribute on the templateId element contains a known UID that identifies this entry as the one I want. I need to get the reference value.
My thought is to find the correct templateID node, back out to the observation node, find <valuexsi:type="ED"> and then get the reference value. This seems overly complex, and I am wondering if there is another way to do this?
EDIT
The xml I receive can sometimes have xml nested under the same node name. In other words, <observation> may be located under another node named <observation>.
You have problems, because your document uses Namespaces, and your query is missing them.
First of all, you have to find xsi namespace declaration somewhere in your XML (probably in the most top element).
It will look like that:
xmlns:xsi="http://test.namespace"
The, take the namespace Uri and create XNamespace instance according to it's value:
var xsi = XNamespace.Get("http://test.namespace");
And use that xsi variable within your query:
var query = from o in xdoc.Root.Element("entries").Elements("entry").Elements("observation")
let tId = o.Element("templateId")
where tId != null && (string)tId.Attribute("root") == "2.16.840.1.113883.10.20.6.2.12"
let v = o.Element("value")
where v != null && (string)v.Attribute(xsi + "type") != null
let r = v.Element("reference")
where r != null
select (string)r.Attribute("value");
var result = query.FirstOrDefault();
I have tested it for following XML structure:
<root xmlns:xsi="http://test.namespace">
<entries>
<entry>
<observation classCode="OBS" moodCode="EVN">
<templateId root="2.16.840.1.113883.10.20.6.2.12" />
<code code="121070" codeSystem="1.2.840.10008.2.16.4" codeSystemName="DCM" displayName="Findings">
</code>
<value xsi:type="ED">
<reference value="#121071">
</reference>
</value>
</observation>
</entry>
</entries>
</root>
The query returns #121071 for it.
For your input XML you will probably have to change first line of query:
from o in xdoc.Root.Element("entries").Elements("entry").Elements("observation")
to match <observation> elements from your XML structure.
Would something along the lines of the following help?
XDocument xdoc = GetYourDocumentHere();
var obsvlookfor =
xdoc.Root.Descendants("observation")
.SingleOrDefault(el =>
el.Element("templateId")
.Attribute("root").Value == "root value to look for");
if (obsvlookfor != null)
{
var reference = obsvlookfor
.Element("value")
.Element("reference").Attribute("value").Value;
}
My thought is as follows:
Pull out all the observation elements in the document
Find the only one (or null) where the observation's templateId element has a root attribute you're looking for
If you find that observation element, pull out the value attribute against the reference element which is under the value element.
You might have to include the Namespace in your LINQ. To retrieve that you would do something like this:
XNamespace ns = xdoc.Root.GetDefaultNamespace();
Then in your linq:
var obsvlookfor = xdoc.Root.Descendants(ns + "observation")
I know I had some issues retrieving data once without this. Not saying its the issue just something to keep in mind particularly if your XML file is very in depth.
given this xml (just a part..)
<?xml version="1.0" encoding="utf-8"?>
<translations>
<key name="BillOfMaterials">
<translation culture="en-GB"><![CDATA[Bill of materials]]>
</translation>
<translation culture="da-DK"><![CDATA[Materiale liste]]>
</translation>
</key>
<key name="TechnicalDetails">
<translation culture="en-GB">
<![CDATA[Technical details
]]>
</translation>
</key>
..
..
...i'm looking for the simplest solution to look up for instance:
so
string thisTranslation = GetTranslation("BillOfMaterials","en-GB"); //value gets to be "Bill of materials"
I have tried the linq way, but it gets rather messy with too many itherations... especially when a simple xpath is enough in xslt... But I can't seem to just do that
Thanks in advance
Edit:
- xml is physical file
- function may not find anything.....should then just return the original key name
/translations/key[#name="BillOfMaterials"]/translation[#culture="en-GB"]
is the xpath that elsewhere is usable..
I would still use LINQ to XML - there's absolutely no need for it to get messy:
XDocument doc = XDocument.Load("test.xml");
string key = "BillOfMaterials";
var element = doc.Root.Elements("key")
.Where(key => key.Attribute("name").Value == key)
.Elements("translation")
.Where(tr => tr.Attribute("culture").Value == "en-GB")
.FirstOrDefault();
string result = (string) element ?? key;
Personally I find that cleaner than using XPath (even though the XPath is undeniably shorter). It separates each section of the query more distinctly, and also if you need any namespace handling, that would be significantly simpler with LINQ to XML than messing around with namespace managers.
You can use XPathSelectElement extension method set on XElement with your XPath selector:
Load your XML into an XDocument:
var doc = XDocument.Load("path\to\file");
and then search it with XPath:
var translation = (string)doc.XPathSelectElement(string.format("/translations/key[#name=\"{0}\"]/translation[#culture=\"{1}\"]", key, culture));
if(string.IsNullOrEmpty(translation))
translation = key;
return translation;
Get you Xml document in a XmlDocument type. You can do this like:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("<xml>"); // Can be a XML in a string, or filename, etc.
Then you can use XPath with the SelectNodes() and SelectNode() methods.
Like:
XmlNodeList xmlNodes = xmlDoc.SelectNodes("/translations/key[#name=\"BillOfMaterials\"]/translation[#culture=\"en-GB\"]");
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>