Simple XML parsing with LINQ - c#

I would like to parse this XML :
<?xml version="1.0" encoding="Windows-1252" ?>
<TEST>Login inexistant</TEST>
I wrote this code
var result = from item in XElement.Parse(m_strRetour).Descendants("TEST")
select item;
return result.First().ToString();
m_strRetour is a string that contains my XML.
After execution, result is empty.
What am I doing wrong?

TEST seems to be your root node, so it can't be a Descendant.
To get the value out of it you could try this.
var xml = "<?xml version='1.0' encoding='Windows-1252' ?><TEST>Login inexistant</TEST>";
var result = XElement.Parse(xml);
var value = result.Value;

XElement.Parse will return the TEST element itself - which doesn't have any descendants. (Also, there's no benefit in using a query expression here. Whenever you write from x in y select x you should consider whether you couldn't just use y instead...)
You could parse it as an XDocument instead, in which case there would be a TEST descendant... or you could just use the XElement itself.
What are you really trying to achieve though? Does your real XML only have a single element?

Related

XML: Retrieve a particular value from xml

From the following XML, I want to find a value based on the Employer.
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<Details>
<Employer>Taxes</Employer>
<Adr>
<Strt>Street</Strt>
<Twn>Town</Twn>
</Adr>
</Details>
<DetailsAcct>
<Recd>
<Payroll>
<Id>9</Id>
</Payroll>
</Recd>
<br>
<xy>A</xy>
</br>
</DetailsAcct>
</Document>
the C# code I applied is
detail = root.SelectSingleNode($"//w:Document//w:Employer[contains(text(), 'Taxes']/ancestor::Employer",nsmgr);
But it gives me an invalid token error.
What am I missing?
The error was due to [contains(...], notice closing parentheses is missing. And since you want to return Employer element, no need for ancestor::Employer here :
//w:Document//w:Employer[contains(., 'Taxes')]
If the XML posted resembles structure of the actual XML (except the namespaces), better to use more specific XPath i.e avoid using costly // :
/w:Document/w:Details/w:Employer[contains(., 'Taxes')]
An alternative is to use LINQ to XML.
If the XML is in a string:
string xml = "<xml goes here>";
XDocument document = XDocument.Parse(xml);
XElement element = document.Descendants("Employer").First();
string value = element.Value;
If the XML is in a .xml file:
XDocument document = XDocument.Load("xmlfile.xml");
XElement element = document.Descendants("Employer").First();
string value = element.Value;
You can also find an employer element with a specific value, if that's what you need:
XElement element = document.Descendants("Employer").First(e => e.Value == "Taxes");
Note: this will throw an exception if no element is found with the specified value. If that is not acceptable, then you can replace .First(...) with .FirstOrDefault(...) which will simply return null if no element is found.

c# extract value from nextnode

I have the following xml part and am trying to extract the value where key is known. The example below is a snippet, from a larger xml that contains 1000's of nodes.
<?xml version="1.0" encoding="utf-8"?>
<DictionarySerializer>
<item>
<key>key1</key>
<value>CONTENT1</value>
</item>
<item>
<key>key2</key>
<value>CONTENT2</value>
</item>
</DictionarySerializer>
i assume the above is a string called xml,
then with
XDocument.Parse(xml)
.Descendants("key")
.Where(x => (string)x.Value == "key1")
.FirstOrDefault().NextNode.ToString()
I can get the string <value>CONTENT1</value> But i simply cannot get my head around how to get the value of the value node to to say.
I am afrad it is super simple, and i just are stuck in a coffein loop :-)
XDocument.Parse(xml)
.Descendants("key")
.Where(x => (string)x.Value == "key1")
.FirstOrDefault().Value.ToString()
you should use .Value property instead of .NextNode
If you want to get all keys and values from the XML from all 1000 elemnts. You can use:
Dictionary<string, string> elements = new Dictionary<string, string>();
xml.Root.Elements().ToList().ForEach(xmlElement =>
{
elements.Add(xmlElement.Descendants("key").First().Value,
xmlElement.Descendants("value").First().Value);
});
So, the elements dictionary will contain all of your 1000 nodes.
Try to cast NextNode to XElement and get Value from it.
Considering you can use XPath expressions.
expression = #"//Item[Key='1']/Value"
XmlNodeList nodeList = xmlDocument.SelectNodes(expression);
This would give you the value node(s) of items with Key=1. Just find the value of the desired node.
I believe using XDocument you can also try,
string output = xDocument.XPathEvaluate(expression);

Trying to read xml file with LINQ

I am trying to get the variable whitch is an integer, but it gives me a string.
XDocument xmlDoc = XDocument.Load(path);
var test = xmlDoc.Descendants("Variables").Elements("nom").Select(e => (int)e);
Console.WriteLine(test);
here is my xml file
<?xml version="1.0" encoding="utf-8"?><Variables><Site>Chand</Site><nom>12</nom></Variables>
The expression you entered is of type IEnumerable<int> and not a single int. Try appending .First() to get the first (and in this case only) element of the enumerable.
var test = xmlDoc.Descendants("Variables").Elements("nom").Select(e => (int)e).First();

xml Nodes by Element

Below is an example of the xml file that I need to pull data via C#. This is my first experience with reading xml files and a beginner with xml. Anyone have an example of how I would find/load the fieldorder values for Export_B?
<?xml version="1.0" encoding="utf-8"?>
<Config>
<OutFolderCSV>c:\Output\2012\upload_Files</OutFolderCSV>
<OutFolderImage>c:\Output\2012\NM_Scorecard_Images</OutFolderImage>
<PathOutLogFile>c:\Output\2012\Log\Matches.log</PathOutLogFile>
<FieldSeparator>,</FieldSeparator>
<ExportFile>
<Name>Export_A</Name>
<FieldOrder>matchID</FieldOrder>
<FieldOrder>contactID</FieldOrder>
<FieldOrder>stageID13</FieldOrder>
<FieldOrder>stringScore1a</FieldOrder>
<FieldOrder>xScore1a</FieldOrder>
<FieldOrder>stageID14</FieldOrder>
<FieldOrder>stringScore1b</FieldOrder>
<FieldOrder>xScore1b</FieldOrder>
<FieldOrder>stageID15</FieldOrder>
<FieldOrder>stringScore1c</FieldOrder>
<FieldOrder>xScore1c</FieldOrder>
</ExportFile>
<ExportFile>
<Name>Export_B</Name>
<FieldOrder>matchID</FieldOrder>
<FieldOrder>contactID</FieldOrder>
<FieldOrder>stageID16</FieldOrder>
<FieldOrder>stringScore1a</FieldOrder>
<FieldOrder>xScore1a</FieldOrder>
<FieldOrder>stageID17</FieldOrder>
<FieldOrder>stringScore1b</FieldOrder>
<FieldOrder>xScore1b</FieldOrder>
<FieldOrder>stageID18</FieldOrder>
<FieldOrder>stringScore1c</FieldOrder>
<FieldOrder>xScore</FieldOrder>
</ExportFile>
</Config>
Using LINQ to XML:
var doc = XDocument.Load(#"c:\path\to\file.xml");
var fieldOrders =
from exportFile in doc.Descendants("ExportFile")
where (string)exportFile.Element("Name") == "Export_B"
from fieldOrder in exportFile.Elements("FieldOrder")
select (string)fieldOrder;
I have written an article
http://www.codeproject.com/Articles/33769/Basics-of-LINQ-Lamda-Expressions
on XML using XDocument object.
You can parse the XML easily using
XDocument.Load(filepath)
Please read the section XLinq to parse the objects.
edit :
You can change value of Export_B using the code :
var document = XDocument.Load(filepath)
var exportFiles = document.Descandants("ExportFile");
List<XElement> list = new List<XElement>();
foreach(var element in exportFiles)
{
list.Add(element);
// Now you can do element.Element("Name") to get the name. Put a breakpoint on this, you can get the reference of all underlying objects.
}

Can I avoid having to use fully-qualified element names in LINQ to XML?

Say I call XElement.Parse() with the following XML string:
var xml = XElement.Parse(#"
<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Owner>
<ID>7c75442509c41100b6a413b88b523bd6f46554cdbee5b6cbe27bc08cb3f6a865</ID>
<DisplayName>me</DisplayName>
</Owner>
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
...
");
When it comes time to query the element, I'm forced to use fully-qualified element names because that XML document contains an xmlns attribute in its root. This requires cumbersome creations of XName instances:
var AWS_XMLNS = "http://s3.amazonaws.com/doc/2006-03-01/";
var ownerElement = xml.Element(XName.Get("AccessControlPolicy", AWS_XMLNS)).Element(XName.Get("Owner", AWS_XMLNS));
When what I really want is simply,
var ownerElement = xml.Element("AccessControlPolicy").Element("Owner");
Is there a way to make LINQ to XML assume a specific namespace so I don't have to keep specifying it?
You could simplify by using
XNamespace ns = "http://s3.amazonaws.com/doc/2006-03-01/";
var ownerElement = xml.Element(ns + "AccessControlPolicy").Element(ns + "Owner");
I don't think you can (see Jon Skeet's comment), but there are a few tricks you can do.
1) create an extension method that appends the XNamespace to your string
2) Use VB?!?

Categories