I have the below XML in a data definitions file:
<PQTemplate documentID="CSTrlsEN" documentType="TransList" templateID="001"
templateType="Customer Copy"
templateName="C:\CPS\_templates\Mini-Statements\CSTrlsEN.doc">
<field pos="5" name="YPTME" descr="Time" />
<field pos="6" name="YPDTE" descr="Action Date" />
<field pos="7" name="YPBRNO" descr="Branch Number" />
<field pos="8" name="YPBNA" descr="Branch Name" />
<field pos="9" name="YPTID" descr="Teller ID" />
<field pos="10" name="YPISN" descr="Teller Sequence" />
<field pos="11" name="YPREF" descr="Customer Reference" />
<field pos="12" name="YPCUS" descr="Customer Name" />
<field pos="13" name="YPEAN" descr="Account Number" />
<field pos="14" name="YPATY" descr="Account Type" />
<field pos="15" name="YPCUR" descr="Currency" />
<field pos="16" name="YPBAL" descr="Available Balance" />
I get that specific XElement using LINQ, extracting it from an XML file that contains several PQTemplate elements by using the below LINQ Expression:
var mapInfo = from nm in XElement.Elements("PQTemplate")
where (string)nm.Attribute("documentID") == sRequests[0].Split('\t')[0]
select nm;
Now I need to get the value of the attribute documentType so I tried the below LINQ Expression:
var repName = from d in mapInfo.Attributes("documentType")
select d.Value;
reportName = repName.ToString();
Unfortunately although I can see the value TransList is part of the reportName element, I have had no luck trying to retrieve it.
Here is an image showing it in VS 2013:
so how can I get the documentType attribute in the element?
That's because repName will return an IEnumerable<string> for all the mapInfo.
IEnumerable<string> repName = from d in mapInfo.Attributes("documentType")
select d.Value;
So either use a foreach loop if you suspect you may get more values or use First to get first attribute like this:-
string reportName = mapInfo.First().Attribute("documentType").Value;
Linq queries return collections. Do for each over repName or
repName.First().ToString()
if that is all you need.
Your solution depends on how many elements DocumentType exist in your XML. If it´s only one (what I suppose) you may use repName.First().ToString().
If the attribute may occure more than once you should use a loop instead:
var result = new List<string>();
foreach(var a in (from d in mapInfo.Attributes("documentType") select d.Value)
result.Add(a.ToString());
Or even shorter:
result = mapInfo.Attributes("documentType").Select(x => x.Value.ToString());
Which will return an enumeration.
Change
var mapInfo = from nm in XElement.Elements("PQTemplate")
where (string)nm.Attribute("documentID") == sRequests[0].Split('\t')[0]
select nm;
to
var mapInfo = from nm in XElement.Elements("PQTemplate")
where (string)nm.Attribute("documentID") == sRequests[0].Split('\t')[0]
select nm.Attribute("documentType").Value;
then mapInfo.First() will give you the value you want.
To get a single value out of a LINQ query you have to call for example First or FirstOrDefault. If you call FirstOrDefault it won't throw an exception if the query returns no matches.
string repName = doc.Elements("PQTemplate")
.Where(e => (string)a.Attribute("documentID") == sRequests[0].Split('\t')[0])
.Select(e => (string)e.Attribute("documentType"))
.FirstOrDefault();
Also, you don't need to call ToString() on XAttribute.Value as it's already a string.
Related
I have an XElement as follows
<row>
<field name="field1">Test1</field>
<field name="field2">Test2</field>
<field name="field3">Test3</field>
</row>
I want to retrieve value Test2 using the attribute value field2 using LINQ.I tried the following code
var data= item.Elements("field").Single(x => x.Attribute("name").Value == "field2");
It's not working.When I run the code it fails with error Sequence contains no matching element >
I don't know what I'm missing here.How can I retrieve the value using LINQ
I found the mistake. The code should be like this
var data = item.Elements().Single(x => x.Attribute("name").Value == "field2").Value;
In this xml file (http://www.studiovincent.net/list.xml):
<list version="1.0">
<meta>
<type>resource-list</type>
</meta>
<resources start="0" count="4">
<resource classname="Quote">
<field name="name">Vincent</field>
<field name="username">Hill</field>
<field name="age">31</field>
<field name="hair">black</field>
</resource>
<resource classname="Quote">
<field name="name">John</field>
<field name="username">Tedelon</field>
<field name="age">27</field>
<field name="hair">brown</field>
</resource>
<resource classname="Quote">
<field name="name">Michael</field>
<field name="username">Lopez</field>
<field name="age">20</field>
<field name="hair">red</field>
</resource>
<resource classname="Quote">
<field name="name">Frank</field>
<field name="username">Lopez</field>
<field name="age">25</field>
<field name="hair">black</field>
</resource>
</resources>
</list>
using this code:
using System.Xml;
using.System.Xml.Linq;
XmlReader reader = XmlReader.Create("http://www.studiovincent.net/list.xml");
XElement el = XElement.Load(reader);
reader.Close();
var items = el.Elements("resources").Elements("resource").Descendants().DescendantNodes();
var items = from item in el.Elements("resources").Elements("resource").Descendants()
where item.Attribute("name").Value == "name" select item.FirstNode;
foreach (XNode node in items)
{
Console.WriteLine(node.ToString());
}
I have this OUTPUT:
Vincent
John
Michael
Frank
Code working very good, but I need get value 31 which corresponds field name="age" where field name="name" is Vincent. How Can I get this result?
I recommend you do as you would when reading XML naturally.
In your code, try to find all the fields with the name attribute set to "name".
This process cannot be used to associate a name with an age. It is more natural to read the XML and check all resource elements. Then add to this element some information described in the field elements.
// Using LINQ to SQL
XDocument document = XDocument.Load("http://www.studiovincent.net/list.xml"); // Loads the XML document.
XElement resourcesElement = document.Root.Element("resources"); // Gets the "resources" element that is in the root "list" of the document.
XElement resourceElementVincent = (from resourceElement in resourcesElement.Elements("resource")// Gets all the "resource" elements in the "resources" element
let fieldNameElement = resourceElement.Elements("field").Single(fieldElement => fieldElement.Attribute("name").Value == "name") // Gets the field that contains the name (there one and only one "name" field in the "resource" element -> use of Single())
where fieldNameElement.Value == "Vincent" // To get only resources called "Vincent"
select resourceElement).Single(); // We suppose there is one and only 1 resource called "Vincent" -> Use of Single()
XElement fieldAgeElement = resourceElementVincent.Elements("field").Single(fieldElement => fieldElement.Attribute("name").Value == "age"); // Gets the corresponding "age" field
int age = int.Parse(fieldAgeElement.Value, CultureInfo.InvariantCulture); // Gets the age by Parse it as an integer
Console.WriteLine(age);
Does it do what you want?
Consider this below XML is there as one of the SQL table's column.
<Root>
<Name>Dinesh</Name>
<Id>2</Id>
</Root>
The objective of the query is to fetch the Name from the XML. In this example we will fetch the 'Dinesh' as the value.
var Query = (from t in dbContext.Employee.AsEnumerable()
where t.active == true
select new Employee
{
Id = t.AtpEventId,
Name = XDocument.Parse(t.Content).Descendants("Root").Descendants("Name").ToList().
Select(node => node.Value.ToString()).FirstOrDefault()
});
Note the following:
t.active == true is just an example to make some condition if needed.
Please note, in the above LINQ query, always use the AsEnumerable, as I did in the first line.
Descendants("Root").Descendants("Name") - here "Root" should be the element matching with the XML, and under Root we have Name element.
have an XML file like this:
<VS>
<Fields>
<Field Id="$1*">Column1</Field>
<Field Id="$2*">Column2</Field>
<Field Id="$3*">Column3</Field>
</Fields>
</VS>
When I use LINQ to XML using the following statement:
XDocument doc = XDocument.Parse(s);
var q = doc.Descendants("Fields").ToList();
I get a single entry in list as Column1Column2Column3, whereas I want it as 3 separate entities like Column1, Column2, Column3.
Can anyone help?
Use Field instead of Fields:
var q = doc.Descendants("Field").ToList();
you should use XElement.Parse(BuildNode.InnerXml) instead of just passing the raw property in.
Check This
Just used the following code which returned list of strings.
var q = doc.Descendants("Field").Select(x => x.Value);
Thanks for all your suggestions!
I am using traditional XmlReader to parse a xml document into a dictionary? However i am in search for less complicated method minimum lines of code. I have the following Xml document
<Msg>
<field id="0" value="0100"/>
<field id="3" value="310000"/>
<field id="7" value="0101150110"/>
<field id="11" value="000002"/>
</Msg>
Is it possible to split the following xml document into a dictionary object with key being the attribute and value being the value of that element?
eg:-
Key = 0 value =0100
Rather than using XmlReader, I'd suggest using LINQ to XML, at which point it's really simple:
var dictionary = document.Descendants("field")
.ToDictionary(x => (int) x.Attribute("id"),
x => (string) x.Attribute("value"));
var query = (from element in document.Descendants("field"))
.ToDictionary(pair => (int)pair.Attribute("id"),
pair => (string)pair.Attribute("value"));
I have this XML document :
<?xml version="1.0" encoding="UTF-8"?>
<teryt>
<catalog name="TERC" type="all" date="2010-01-01">
<row>
<field name="Woj">1</field>
<field name="City">Warszawa</field>
<field name="Name">Mazowsze</field>
</row>
<row>
<field name="WojId">1</field>
<field name="City"/>
<field name="Name">Mazowsze</field>
</row>
<row>
<field name="Woj">2</field>
<field name="City"/>
<field name="Name">Slask</field>
</row>
</catalog>
</teryt>
And now I want to get only rows which don't have value in field with attribute City (using LINQ to XML).
Do you mean something like:
var rows = from row in doc.Root.Elements("rows")
where !row.Elements("field")
.Any(x => (string) x.Attribute("name") == "City"
&& x.Value != "")
select row;
That says, "find all rows which don't have any non-empty field elements with a name attribute of City". I think that's what you're after...
Something like:
var query = from row in xdoc.Descendants("row")
where row.Elements("field")
.Any(ff => ff.Attribute("name").Value == "City"
&& String.IsNullOrWhitespace(ff.Value))
select row;
This is predicated on the desire to find every row without a City value.
Once you have loaded your xml document into an XDocument object you can access its tags. So you should grab the Root element of your XDocument and navigate down to the row tags with the Elements method. And when you have all your tags in a collection you can sort out the ones with no city field. I'm almost sure that there is a HasValue property on the xml elements which tells you if it has value or not. But if there isn't one, you can check the Value property which would be empty or null.
So now a little code for this, the way I like:
XDocument doc = XDocument.Load("yourfile");
var tags = doc.Root.Element("catalog")
.Elements("row")
.Where(r=>r.Elements("field")
.Single(f=>f.Attribute("name").Value == "City"
&& string.IsNullOrWhitespace(f.Value)));
It translates into something like this: Take the document, select the root of the document, take the element named "catalog", and give me all the "row" elements, where it is true, that if the "row" has a "field" element with the "name" attribute set to "City", it is null, empty string, or whitespace.
Now this may not be so easy to understand if you are new to this, but this is the way I would do it. You may add a few null-checks but this is up to you now.