I have tried to parse an XML file like this:
<books>
<book>
<attr name="Moby Dick">Moby Dick is a classic</attr>
<attr isbn="isbnNumber">123456789</attr>
</book>
</books>
How can I get the value of "123456789"? I don't really need the first attribute.
I tried reading these in a foreach loop getting XElements but I keep getting a NULL object exception.
foreach(XElement xe in XDoc.Attribute("attr"))
{
string str = xe.Attribute("isbnNumber").Value // NULL EXCEPTION HERE
}
Thanks in advance...
You could try using the XPathSelectElement() extension method [you'll need to use System.Xml.XPath to get them].
E.g.
var isbn = xDoc.XPathSelectElement("//book/attr[#isbn='isbnNumber']").Value
PS. A good XPath tester is at: http://www.yetanotherchris.me/home/2010/6/7/online-xpath-tester.html
123456789 is actually the value of an element, not an attribute. What you want can be done like so:
XElement attr = xDoc.Descendants("attr")
.FirstOrDefault( x=>
(string)x.Attribute("isbn") == "isbnNumber"
);
string isbn = (string)attr;
You could even make it one line but this might be easier to read if you're new to LINQ to XML.
Well, I can't figure out how to respond to the individual answers..... but I implemented them both and they both work.
I am going with Reddog's answer as it is a little more straightforward and being new to LINQ it is the easiest as of now for readability.
Thanks for the responses!
Related
I have few solutions on how to do this, but I was wondering if there is a neat way to do this.
<Project>
<Test>
<Name value="zero">
<Name value="One">
<Name value="Two">
</Test>
</Project>
Now, I have access to testElement. I want to add new child XElement to it, only when it doesn't exist.
What I am currently doing is this. This is only sample code I am typing which is equivalent to what I am doing, so pardon me for minor mistakes.
XElement element = (from item
in testElement.Elements("name")
where item.Attribute("value") == "zero"
select item).SingleOrDefault();
if (element == null)
{
testElement.add(newElement);
}
Is there is a better way to do this? Maybe a simpler check?
you may perhaps use XPath extensions available via using System.Xml.XPath; to avoid lengthy LINQ, this is pretty simpler and easy
example
XElement element = testElement.XPathSelectElement("Name[#value='zero']");
if (element == null)
{
testElement.add(newElement);
}
XPath Name[#value='zero'] in the example above says that you are looking for an element named Name which has an attribute # named value and has the value of zero. so the linq in the question is reduced to on single XPathSelectElement and rest remains same.
optional, this is just a rewrite of above code
if (testElement.XPathSelectElement("Name[#value='zero']") == null)
{
testElement.add(newElement);
}
You are comparing an XAttribute to a string, so you probably are not getting the result you want.
item.Attribute("value") == "zero"
Try changing it to:
(string)item.Attribute("value") == "zero"
This converts the attribute to a string before the comparison.
I have an XML string like below:
<root>
<Test1>
<Result time="2">ProperEnding</Result>
</Test1>
<Test2></Test2>
I have to operate on these elements. Most of the time the elements are unique within their parent element. I am using XDocument. I can remember that there is a way to access an element like this.
XNode resultTest1 = GetNodes("/root//Test1//result")
But I forgot it. It is possible to access the same using linq:
doc.root.Elements.etc.etc.
But I want it using a single string as shown above. Can anybody say how to make it?
Descendants() will skip any number level of intermediate nodes, e.g. this will skip over root and Test1:
doc.Decendants("Result")
Also note that you can use XPath with Linq2Xml as well, e.g. XPathSelectElements
doc.XPathSelectElements("/root/Test1/Result");
You can skip intermediate levels of the hierarchy with // (or use // at the start of the xpath string to skip the root)
"/root//Result"
One caveat - Xml is case sensitive , so Result and result are not the same element.
The string you're referring to ("/root//Test1//result") is an XPath expression.
You can use it with LINQ to XML classes (like XDocument) using XPathEvaluate, XPathSelectElement, and XPathSelectElements extension methods.
You can find more info about these methods on MSDN: http://msdn.microsoft.com/en-us/library/vstudio/system.xml.xpath.extensions_methods(v=vs.90).aspx
To make them work, you need using System.Xml.XPath at the top of your file and System.Xml.Linq.dll assembly referenced (which is probably already there).
You can try to load your xml using XDocument:
// loads xml file with root element
XDocument xml = XDocument.Load("filename.xml");
Now you can append LINQ statements to your xml variable like this:
var retrieveSomeSpecificDataLikeListOfElementsAsAnonymousObjects = xml.Descendants("parentNodeName").Select(node => new { SomeSpecialValueYouWant = node.Element("elementNameUnderParentNode").Value }).ToList();
You can mix and do whatever you want - above is just an example.
Is this what you looking?
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml("YourXML");
XmlNodeList xmlNodes = xmlDocument.SelectNodes("/root/Test1/result");
I want to extract an svg element by his class name with a C# regex.
For example I have this:
<path fill="none" ... class="highcharts-tracker highcharts-tracker" ... stroke-width="22" zIndex="2" style=""/>
And I want to delete every path elements with highcharts-tracker as class name by using :
new Regex("");
Anybody know ?
In LINQ to XML, this is pretty straightforward:
var classToRemove = "highlights-tracker";
var xml = XDocument.Parse(svg);
var elements = doc.Descendants("path")
.Where(x => x.Attribute("class") != null &&
x.Attribute("class")
.Value.Split(' ')
.Contains(classToRemove));
// Remove all the elements which match the query
elements.Remove();
You should not use regular expressions to try to parse XML... XML is very well handled by existing APIs, and regular expressions are not an appropriate tool.
EDIT: If it's malformed (which you should have said to start with) you should try to work out why it's malformed and fix it before you try to do any other processing. There's really no excuse for XML being malformed these days... there are plenty of good XML APIs for just about every platform in existence.
I'm Trying to check XML elements for specific attributes so I can keep from saving duplicate element entries. the XML looks more or less like this:
<root>
<artist name="Coldplay">
<track name="yellow" artist="Coldplay" url="coldplay.com/yellow" playCount="123" />
<track name="fix you" artist="Coldplay" url="coldplay.com/fixyou" playCount="135" >
</artist>
//ect.
</root>
google and various search results suggest something like
[#id='foo']
but i don't know what that is and for reasons that might be more obvious to you than to me i can't "google" a collection of special characters like that without getting bizarre results. So If anyone can offer a suggestion for an if checking statement I'd be much obliged! or a name or link for how special characters are used in C#.
It's an XPath expression. You can use them along with a variety of XML-related objects in c#.
XmlDocument xd = new XmlDocument();
xd.LoadXml( xmlString );
XmlNodeList nodes = xd.SelectNodes( "//root/artist/track[#name='yellow']" );
General Reference: http://msdn.microsoft.com/en-us/library/ms256086.aspx
XPath with LINQ: http://msdn.microsoft.com/en-us/library/bb675183.aspx.
That's an XPath expression - but personally, I'd use LINQ to XML for the searching myself:
XDocument doc = XDocument.Load("test.xml");
var track = doc.Descendants("track")
.Where(t => (string) t.Attribute("id") == "foo")
.FirstOrDefault();
(Use Single, SingleOrDefault, First etc if you want to.)
For example for the following XML
<Order>
<Phone>1254</Phone>
<City>City1</City>
<State>State</State>
</Order>
I might want to find out whether the XElement contains "City" Node or not.
Just use the other overload for Elements.
bool hasCity = OrderXml.Elements("City").Any();
It's been a while since I did XLinq, but here goes my WAG:
from x in XDocument
where x.Elements("City").Count > 0
select x
;
David's is the best but if you want you can write your own predicate if you need some custom logic OrderXML.Elements("City").Exists(x=>x.Name =="City")