I have an xml file called portfolio that I am passing the location of as a string.
Read a list of filenames from the portfolio file, under the element. In the xml file I have an element called that I need to read the 4 values in the price data and store it to a List of strings. I don't know if I am doing this correctly. I don't know what my parameters should be for the foreach loop.
XML file:
<priceData>
<file name="ibmx.xml"/>
<file name="msft.xml"/>
<file name="ulti.xml"/>
<file name="goog.xml"/>
</priceData>
Here is my function for C#
public static void readPortfolio(string filename)
{
XmlTextReader reader = new XmlTextReader(filename);
reader.Read();
List<string> priceDataFile = new List <string> ();
foreach(var file in reader) //Don't know what the parameters should be.
{
priceDataFile.Add(reader.Value); //Not sure if I am passing what I want
}
}
Using XDocument Class is a good way to solve it.But if you want to use XmlTextReader Class, the code has been listed as follow. Then you will get the result which contains a XML file list. On the onther way, name is an attribute in your example code. So you should use reader.GetAttribute("name") to get value.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace XmlReaderTest
{
class Program
{
static void Main(string[] args)
{
XmlTextReader reader = new XmlTextReader("../../Portfolio.xml");
reader.WhitespaceHandling = WhitespaceHandling.None;
List<string> priceDataFile = new List<string>();
while (reader.Read())
{
if (reader.Name == "file")
{
priceDataFile.Add(reader.GetAttribute("name"));
}
else
continue;
}
reader.Close();
foreach (string file in priceDataFile)
{
Console.WriteLine(file);
}
Console.ReadLine();
}
}
}
Use LINQ to XML instead (.NET 3.0+):
XDocument doc = XDocument.Load(path);
List<string> list = doc.Root
.Elements("file")
.Select(f => (string)f.Atribute("name"))
.ToList();
You can do this . the following will add the filename of each attribute to the list
replace where I have declared a copy of your .XML file with your path location.
XDocument document = XDocument.Load(#"C:\Sample_Xml\PriceData.xml");
List<string> priceDataFile = new List<string>();
var priceData = (from pd in document.Descendants("priceData")
select pd);
foreach (XElement priceValue in priceData.Elements())
{
priceDataFile.Add(priceValue.FirstAttribute.Value.ToString());
}
this is what your priseDataFile List Contents will look like
viewing it in the QuickWatch
[0] "ibmx.xml"
[1] "msft.xml"
[2] "ulti.xml"
[3] "goog.xml"
Related
I am using c# .net 4.6 xpath to search for node with id value and when found create a new attribute for the parent element in place. I have a list of such id values that I need to iterate over and create attributes to produce a new xml document. I have attempted the following but does not work. The XPathNavigator.MoveTo method appears to replace the source navigator with the moved to element thereby loosing all other content. Is this not the right way to achieve this ? Could you please advice ?
See code snippet below:
publicationDoc.LoadXml(publicationXPathNav.OuterXml);
XPathNavigator publicationNav = publicationDoc.CreateNavigator();
foreach (IListBlobItem item in contentDirectory.ListBlobs())
{
var blob = (CloudBlob)item;
string contentId = blob.Name;
XPathNavigator contentRefNav = publicationNav.SelectSingleNode($#"//releaseItem/contentRef[id = {"'" + contentId + "'"}]/..");
if (contentRefNav != null)
{
publicationNav.MoveTo(contentRefNav); // here publicationNav gets replaced by contentRefNav
publicationNav.CreateAttribute("", "fileName", "", contentFileName);
}
}
// once finished with the foreach I was hoping to be able to save the publicationNav.OuterXml to a new file with the newly added attributes.
Here is a small cut down sample source xml data :
<publicationsRoot>
<publication>
<urn>iso:pub:std:FDIS:74824</urn>
<releaseItems>
<releaseItem>
<languageNeutral>false</languageNeutral>
<type>STANDARD</type>
<contentRef>
<id>92764155</id>
</contentRef>
</releaseItem>
<releaseItem>
<languageNeutral>false</languageNeutral>
<type>STANDARD</type>
<contentRef>
<id>92802320</id>
</contentRef>
</releaseItem>
<releaseItem>
<languageNeutral>false</languageNeutral>
<type>STANDARD</type>
<contentRef>
<id>92801989</id>
</contentRef>
</releaseItem>
<releaseItems>
</publication>
</publicationsRoot>
Try xml linq with a dictionary
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication167
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Dictionary<string, XElement> dict = doc.Descendants("id")
.GroupBy(x => (string)x, y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
string id = "92764155";
string filename = "filename";
if (dict.ContainsKey(id))
{
dict[id].SetAttributeValue("filename", filename);
}
}
}
}
I managed to resolve this by not using XPathNavigator and relying only on XMLDocuent. It appears that XPathNavigator is more suitable for relative paths whereas my requirement was to search specific nodes and update the xml document in place.
publicationDoc.LoadXml(publicationXPathNav.OuterXml);
foreach (IListBlobItem item in contentDirectory.ListBlobs())
{
var blob = (CloudBlob)item;
string contentId = blob.Name;
XmlNode contentRefNode = publicationDoc.SelectSingleNode($#"//releaseItem/contentRef[id = {"'" + contentId + "'"}]/..");
if (contentRefNode != null)
{
XmlAttribute fileName = publicationDoc.CreateAttribute("fileName");
fileName.Value = contentFileName + contentFileExt;
contentRefNode.Attributes.SetNamedItem(fileName);
}
}
// once finished with the foreach I was hoping to be able to save the publicationNav.OuterXml to a new file with the newly added attributes.
Thanks for all the answers. I will certainly take those on board.
How do I read and parse an XML file in C#?
XmlDocument to read an XML from string or from file.
using System.Xml;
XmlDocument doc = new XmlDocument();
doc.Load("c:\\temp.xml");
or
doc.LoadXml("<xml>something</xml>");
then find a node below it ie like this
XmlNode node = doc.DocumentElement.SelectSingleNode("/book/title");
or
foreach(XmlNode node in doc.DocumentElement.ChildNodes){
string text = node.InnerText; //or loop through its children as well
}
then read the text inside that node like this
string text = node.InnerText;
or read an attribute
string attr = node.Attributes["theattributename"]?.InnerText
Always check for null on Attributes["something"] since it will be null if the attribute does not exist.
LINQ to XML Example:
// Loading from a file, you can also load from a stream
var xml = XDocument.Load(#"C:\contacts.xml");
// Query the data and write out a subset of contacts
var query = from c in xml.Root.Descendants("contact")
where (int)c.Attribute("id") < 4
select c.Element("firstName").Value + " " +
c.Element("lastName").Value;
foreach (string name in query)
{
Console.WriteLine("Contact's Full Name: {0}", name);
}
Reference: LINQ to XML at MSDN
Here's an application I wrote for reading xml sitemaps:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Xml;
namespace SiteMapReader
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter the Location of the file");
// get the location we want to get the sitemaps from
string dirLoc = Console.ReadLine();
// get all the sitemaps
string[] sitemaps = Directory.GetFiles(dirLoc);
StreamWriter sw = new StreamWriter(Application.StartupPath + #"\locs.txt", true);
// loop through each file
foreach (string sitemap in sitemaps)
{
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// cycle through each child noed
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
// first node is the url ... have to go to nexted loc node
foreach (XmlNode locNode in node)
{
// thereare a couple child nodes here so only take data from node named loc
if (locNode.Name == "loc")
{
// get the content of the loc node
string loc = locNode.InnerText;
// write it to the console so you can see its working
Console.WriteLine(loc + Environment.NewLine);
// write it to the file
sw.Write(loc + Environment.NewLine);
}
}
}
}
catch { }
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
static void readSitemap()
{
}
}
}
Code on Paste Bin
http://pastebin.com/yK7cSNeY
There are lots of way, some:
XmlSerializer. use a class with the target schema
you want to read - use XmlSerializer
to get the data in an Xml loaded into
an instance of the class.
Linq 2 xml
XmlTextReader.
XmlDocument
XPathDocument (read-only access)
You could use a DataSet to read XML strings.
var xmlString = File.ReadAllText(FILE_PATH);
var stringReader = new StringReader(xmlString);
var dsSet = new DataSet();
dsSet.ReadXml(stringReader);
Posting this for the sake of information.
You can either:
Use XmlSerializer class
Use XmlDocument class
Examples are on the msdn pages provided
Linq to XML.
Also, VB.NET has much better xml parsing support via the compiler than C#. If you have the option and the desire, check it out.
Check out XmlTextReader class for instance.
There are different ways, depending on where you want to get.
XmlDocument is lighter than XDocument, but if you wish to verify minimalistically that a string contains XML, then regular expression is possibly the fastest and lightest choice you can make. For example, I have implemented Smoke Tests with SpecFlow for my API and I wish to test if one of the results in any valid XML - then I would use a regular expression. But if I need to extract values from this XML, then I would parse it with XDocument to do it faster and with less code. Or I would use XmlDocument if I have to work with a big XML (and sometimes I work with XML's that are around 1M lines, even more); then I could even read it line by line. Why? Try opening more than 800MB in private bytes in Visual Studio; even on production you should not have objects bigger than 2GB. You can with a twerk, but you should not. If you would have to parse a document, which contains A LOT of lines, then this documents would probably be CSV.
I have written this comment, because I see a lof of examples with XDocument. XDocument is not good for big documents, or when you only want to verify if there the content is XML valid. If you wish to check if the XML itself makes sense, then you need Schema.
I also downvoted the suggested answer, because I believe it needs the above information inside itself. Imagine I need to verify if 200M of XML, 10 times an hour, is valid XML. XDocument will waste a lof of resources.
prasanna venkatesh also states you could try filling the string to a dataset, it will indicate valid XML as well.
public void ReadXmlFile()
{
string path = HttpContext.Current.Server.MapPath("~/App_Data"); // Finds the location of App_Data on server.
XmlTextReader reader = new XmlTextReader(System.IO.Path.Combine(path, "XMLFile7.xml")); //Combines the location of App_Data and the file name
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
columnNames.Add(reader.Value);
break;
case XmlNodeType.EndElement:
break;
}
}
}
You can avoid the first statement and just specify the path name in constructor of XmlTextReader.
If you want to retrive a particular value from an XML file
XmlDocument _LocalInfo_Xml = new XmlDocument();
_LocalInfo_Xml.Load(fileName);
XmlElement _XmlElement;
_XmlElement = _LocalInfo_Xml.GetElementsByTagName("UserId")[0] as XmlElement;
string Value = _XmlElement.InnerText;
Here is another approach using Cinchoo ETL - an open source library to parse xml file with few lines of code.
using (var r = ChoXmlReader<Item>.LoadText(xml)
.WithXPath("//item")
)
{
foreach (var rec in r)
rec.Print();
}
public class Item
{
public string Name { get; set; }
public string ProtectionLevel { get; set; }
public string Description { get; set; }
}
Sample fiddle: https://dotnetfiddle.net/otYq5j
Disclaimer: I'm author of this library.
I have xml stored in string variable. from that xml I need to filter data based on StandardValue. I want to extract only those records whose StandardValue is not null & not empty. I tried but my code did not work.
string xmldoc= #"<?xml version=""1.0"" encoding=""utf-8""?>
<TickerBrokerStandardDateLineitem>
<Ticker />
<TickerID />
<TickerBrokerStandardDateLineitemValues>
<TickerBrokerStandardDateLineitemValue>
<TabName>Consensus Model</TabName>
<StandardDate>1Q 2010</StandardDate>
<BRTab>Income Statement</BRTab>
<BRLineItem>NET REVENUES</BRLineItem>
<Action>Extracted</Action>
<StandardLineItem>Net Revenue</StandardLineItem>
<StandardValue>329.623</StandardValue>
</TickerBrokerStandardDateLineitemValue>
<TickerBrokerStandardDateLineitemValue>
<TabName>Consensus Model</TabName>
<StandardDate>2Q 2010</StandardDate>
<BRTab>Income Statement</BRTab>
<BRLineItem>NET REVENUES</BRLineItem>
<Action>Extracted</Action>
<StandardLineItem>Net Revenue</StandardLineItem>
<StandardValue></StandardValue>
</TickerBrokerStandardDateLineitemValue>
<TickerBrokerStandardDateLineitemValue>
<TabName>Consensus Model</TabName>
<StandardDate>2Q 2010</StandardDate>
<BRTab>Income Statement</BRTab>
<BRLineItem>NET REVENUES</BRLineItem>
<Action>Extracted</Action>
<StandardLineItem>Net Revenue</StandardLineItem>
<StandardValue/>
</TickerBrokerStandardDateLineitemValue>
</TickerBrokerStandardDateLineitemValues>
</TickerBrokerStandardDateLineitem>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmldoc);
XmlNodeList nodeList = doc.GetElementsByTagName("TickerBrokerStandardDateLineitemValue");
List<string> list = new List<string>();
foreach (XmlNode item in nodeList)
{
foreach (XmlElement i in item)
{
if (i.Name == "StandardValue")
{
if (i.InnerText == string.Empty)
{
list.Add(item.OuterXml);
}
}
}
}
string a = string.Empty;
foreach (var item in list)
{
a = doc.InnerXml.Replace(item, "");
}
string str1 = doc.OuterXml;
My above code does not work. basically how to filter with xpath that return only those records whose StandardValue is not null & not empty.
How to achieve it with XmlDocument class instead of xdocument.
At end I have to stored filtered record's xml into string. I know XmlDocument class has outer xml property which return full xml.
Give me sample code which will return filter records & stored filter records xml into string.
Use xml linq which is the newer version of the Net xml library :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
XDocument doc = XDocument.Parse(xml);
List<XElement> tickerBrokerStandardDateLineitemValues = doc.Descendants("TickerBrokerStandardDateLineitemValue")
.Where(x => (x.Element("StandardValue") != null) && ((string)x.Element("StandardValue") != string.Empty))
.ToList();
}
}
}
Assuming the input string your provided in the question.
This will select all TickerBrokerStandardDateLineitemValue values that has StandardValue element and it's not empty or white space (normalize-space).
normalize-space:
strips leading and trailing white-space from a string, replaces
sequences of whitespace characters by a single space, and returns the
resulting string.
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlStr); // <input from the question>
var nodes = xmlDoc.SelectNodes("//TickerBrokerStandardDateLineitemValue[StandardValue and string-length(normalize-space(StandardValue))]");
How do I read and parse an XML file in C#?
XmlDocument to read an XML from string or from file.
using System.Xml;
XmlDocument doc = new XmlDocument();
doc.Load("c:\\temp.xml");
or
doc.LoadXml("<xml>something</xml>");
then find a node below it ie like this
XmlNode node = doc.DocumentElement.SelectSingleNode("/book/title");
or
foreach(XmlNode node in doc.DocumentElement.ChildNodes){
string text = node.InnerText; //or loop through its children as well
}
then read the text inside that node like this
string text = node.InnerText;
or read an attribute
string attr = node.Attributes["theattributename"]?.InnerText
Always check for null on Attributes["something"] since it will be null if the attribute does not exist.
LINQ to XML Example:
// Loading from a file, you can also load from a stream
var xml = XDocument.Load(#"C:\contacts.xml");
// Query the data and write out a subset of contacts
var query = from c in xml.Root.Descendants("contact")
where (int)c.Attribute("id") < 4
select c.Element("firstName").Value + " " +
c.Element("lastName").Value;
foreach (string name in query)
{
Console.WriteLine("Contact's Full Name: {0}", name);
}
Reference: LINQ to XML at MSDN
Here's an application I wrote for reading xml sitemaps:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Xml;
namespace SiteMapReader
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter the Location of the file");
// get the location we want to get the sitemaps from
string dirLoc = Console.ReadLine();
// get all the sitemaps
string[] sitemaps = Directory.GetFiles(dirLoc);
StreamWriter sw = new StreamWriter(Application.StartupPath + #"\locs.txt", true);
// loop through each file
foreach (string sitemap in sitemaps)
{
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// cycle through each child noed
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
// first node is the url ... have to go to nexted loc node
foreach (XmlNode locNode in node)
{
// thereare a couple child nodes here so only take data from node named loc
if (locNode.Name == "loc")
{
// get the content of the loc node
string loc = locNode.InnerText;
// write it to the console so you can see its working
Console.WriteLine(loc + Environment.NewLine);
// write it to the file
sw.Write(loc + Environment.NewLine);
}
}
}
}
catch { }
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
static void readSitemap()
{
}
}
}
Code on Paste Bin
http://pastebin.com/yK7cSNeY
There are lots of way, some:
XmlSerializer. use a class with the target schema
you want to read - use XmlSerializer
to get the data in an Xml loaded into
an instance of the class.
Linq 2 xml
XmlTextReader.
XmlDocument
XPathDocument (read-only access)
You could use a DataSet to read XML strings.
var xmlString = File.ReadAllText(FILE_PATH);
var stringReader = new StringReader(xmlString);
var dsSet = new DataSet();
dsSet.ReadXml(stringReader);
Posting this for the sake of information.
You can either:
Use XmlSerializer class
Use XmlDocument class
Examples are on the msdn pages provided
Linq to XML.
Also, VB.NET has much better xml parsing support via the compiler than C#. If you have the option and the desire, check it out.
Check out XmlTextReader class for instance.
There are different ways, depending on where you want to get.
XmlDocument is lighter than XDocument, but if you wish to verify minimalistically that a string contains XML, then regular expression is possibly the fastest and lightest choice you can make. For example, I have implemented Smoke Tests with SpecFlow for my API and I wish to test if one of the results in any valid XML - then I would use a regular expression. But if I need to extract values from this XML, then I would parse it with XDocument to do it faster and with less code. Or I would use XmlDocument if I have to work with a big XML (and sometimes I work with XML's that are around 1M lines, even more); then I could even read it line by line. Why? Try opening more than 800MB in private bytes in Visual Studio; even on production you should not have objects bigger than 2GB. You can with a twerk, but you should not. If you would have to parse a document, which contains A LOT of lines, then this documents would probably be CSV.
I have written this comment, because I see a lof of examples with XDocument. XDocument is not good for big documents, or when you only want to verify if there the content is XML valid. If you wish to check if the XML itself makes sense, then you need Schema.
I also downvoted the suggested answer, because I believe it needs the above information inside itself. Imagine I need to verify if 200M of XML, 10 times an hour, is valid XML. XDocument will waste a lof of resources.
prasanna venkatesh also states you could try filling the string to a dataset, it will indicate valid XML as well.
public void ReadXmlFile()
{
string path = HttpContext.Current.Server.MapPath("~/App_Data"); // Finds the location of App_Data on server.
XmlTextReader reader = new XmlTextReader(System.IO.Path.Combine(path, "XMLFile7.xml")); //Combines the location of App_Data and the file name
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
columnNames.Add(reader.Value);
break;
case XmlNodeType.EndElement:
break;
}
}
}
You can avoid the first statement and just specify the path name in constructor of XmlTextReader.
If you want to retrive a particular value from an XML file
XmlDocument _LocalInfo_Xml = new XmlDocument();
_LocalInfo_Xml.Load(fileName);
XmlElement _XmlElement;
_XmlElement = _LocalInfo_Xml.GetElementsByTagName("UserId")[0] as XmlElement;
string Value = _XmlElement.InnerText;
Here is another approach using Cinchoo ETL - an open source library to parse xml file with few lines of code.
using (var r = ChoXmlReader<Item>.LoadText(xml)
.WithXPath("//item")
)
{
foreach (var rec in r)
rec.Print();
}
public class Item
{
public string Name { get; set; }
public string ProtectionLevel { get; set; }
public string Description { get; set; }
}
Sample fiddle: https://dotnetfiddle.net/otYq5j
Disclaimer: I'm author of this library.
Background
This is my small XML file I made online.
<?xml version="1.0"?>
<movement>
<skill id = "2">
<cooldown>5</cooldown>
</skill>
<skill id = "3">
<cooldown>10</cooldown>
</skill>
</movement>
This is some code I have so far to try to parse it.
string dataPath = Application.dataPath + "/Resources/XML/Skills/";
DirectoryInfo xmlFolder = new DirectoryInfo (dataPath);
FileInfo[] files = xmlFolder.GetFiles ("*.xml");
// Loops through each XML file
foreach (FileInfo file in files) {
XmlDocument xdoc = new XmlDocument ();
xdoc.Load (file.ToString ());
XmlNodeList nodes = xdoc.DocumentElement.SelectNodes ("/movement");
foreach (XmlNode node in nodes) { // Movement Layer
foreach (XmlNode skillNode in node.ChildNodes) {
print (skillNode.Value);
}
}
}
Problem
I am able to access the 5 and 10 values for cooldown, but cannot get the "id" value of the skill. The reason I'm trying to do this is to read the skill IDs into my game and store the information. I pretty much exhausted almost all the methods denoting from XmlNode, such as value and name, but it only returns "skill", and not the value of skill, such as 2 or 3. I feel like I'm missing something really simple here, but I'm having difficulty finding the correct terminology or phrasing for this issue.
LINQ To XML would make this parsing simpler...
static void Main(string[] args)
{
var doc =
#"<?xml version=""1.0""?>
<movement>
<skill id = ""2"" >
<cooldown> 5 </cooldown>
</skill>
<skill id = ""3"" >
<cooldown> 10 </cooldown>
</skill>
</movement> ";
var root = XDocument.Parse(doc);
foreach (var skill in root.Descendants("skill"))
{
Console.WriteLine("Skill: {0} \t CoolDOwn: {1}",
(int)skill.Attribute("id"),
skill.Element("cooldown").Value);
}
Console.ReadLine();
}
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);
var results = doc.Descendants("skill").Select(x => new {
id = (int)x.Attribute("id"),
coolDown = (int)x.Element("cooldown")
}).ToList();
}
}
}
I would not use XMLDocument for querying purposes IMHO. I find XDocument to be an easier extension off of System.Xml.Linq;
EG:
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleTester
{
class Program
{
static void Main(string[] args)
{
//Here I am mocking your file statically, you could iterate here through a file system.
var xml =
"<?xml version=\"1.0\"?><movement><skill id = \"2\"><cooldown>5</cooldown></skill><skill id = \"3\"><cooldown>10</cooldown></skill></movement>";
//Just parse the file from the text obtained from a StreamReader or similar.
var xdoc = XDocument.Parse(xml);
//Chain the events of finding the node(s) you want with 'Elements' then continuing on to more, then you want an Attribute and not a node. Then select it's value.
xdoc.Elements("movement").Elements("skill").Attributes("id")
.Select(x => x.Value)
.ToList()
.ForEach(x => Console.WriteLine(x));
Console.ReadLine();
}
}
}