Reputation: 517
Following XDocument contains (x,y) coordinates stored in the XElement members with different names under attributes 'x','y','x1','y1','z', and 'z1':
<?xml version="1.0" encoding="utf-8"?>
<shapes>
<shape>
<connections />
<foreground>
<strokewidth width="0.1" />
<path>
<move x="1395.6" y="84.6" />
<line x="80.1" y="84.6" />
<curve x1="75.1" y1="84.6" x2="71.1" y2="88.6" x3="71.1" y3="93.6" />
<line x="71.1" y="402.6" />
<close />
</path>
<fillstroke />
</foreground>
</shape>
</shapes>
What is the easiest recommended way to extract only the values of the attribute 'x' from the whole document without looping through all the elements and checking for the particular attribute? Given XML would ideally result with the list of 'x' coordinates:
float[] x= {1395.6, 80.1, 71.1};
float[] x1 = {75.1};
And the same for 'y', 'y1',...
EDIT: Since the coordinates are always in the 'leaf' xml element, I eventually used:
return fileXml.Root.Descendants()
.Where(e => e.HasElements == false) // leaf element
.Where(e => e.Attribute("x") != null)
.Select(c => c.Attribute("x").Value).Select(float.Parse)
.ToList(); // or .ToArray();
It can be wrapped in a helper function as well.
Upvotes: 2
Views: 458
Reputation: 29520
You should the methods of the XmlConvert class instead of float.Parse()
:
float f = XmlConvert.ToSingle(text);
Upvotes: 0
Reputation: 34421
Some people may like this solution and other may not. It is a little complicated but parses entire xml into x,y pairs using xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<KeyValuePair<string, List<KeyValuePair<double, double>>>> instructions = new List<KeyValuePair<string, List<KeyValuePair<double, double>>>>();
foreach (XElement instruction in doc.Descendants("path").FirstOrDefault().Elements())
{
List<KeyValuePair<double, double>> points = new List<KeyValuePair<double, double>>();
for (int i = 0; i < instruction.Attributes().Count(); i += 2)
{
points.Add(new KeyValuePair<double,double>((double)instruction.Attributes().Skip(i).FirstOrDefault(), (double)instruction.Attributes().Skip(i + 1).FirstOrDefault()));
}
instructions.Add(new KeyValuePair<string, List<KeyValuePair<double,double>>>( instruction.Name.LocalName, points));
}
}
}
}
Upvotes: 1
Reputation: 101593
You can use xpath. XPath expression //@x
will match all attributes with name x
:
var doc = XDocument.Parse(yourXml);
float[] x = ((IEnumerable)doc.XPathEvaluate("//@x"))
.OfType<XAttribute>()
.Select(c => float.Parse(c.Value, CultureInfo.InvariantCulture))
.ToArray();
Upvotes: 2