Miroslav Radojević
Miroslav Radojević

Reputation: 517

Extracting Attribute from the whole XDocument

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

Answers (3)

codymanix
codymanix

Reputation: 29520

You should the methods of the XmlConvert class instead of float.Parse():

float f = XmlConvert.ToSingle(text);

Upvotes: 0

jdweng
jdweng

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

Evk
Evk

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

Related Questions