I've got a print button that gives XML data to filling an adobe lifecycle template. I'm trying to compare ROWID in XML with a repeater rowid to make it print the information about the row the button was clicked on.
Int32 rownum = Convert.ToInt32(e.CommandArgument.ToString());
string xmlROWID = Xmld.Descendants("ROWID").First().Value;
Here are 2 of the children in the XML:
<VKRSADL>
<CUSTOMER_SADLS>
<TABLEVALUE>
<ROW>
<ROWID>0</ROWID>
<ID>Съкредитополучател</ID>
<TYPE>48</TYPE>
<TYPEID>1</TYPEID>
<TYPECODE>1</TYPECODE>
<CRSCODE>777</CRSCODE>
<EGN />
<NAME />
<XML>
<SADL0>
<OwnerCrsCode />
<TABLEVALUE />
</SADL0>
</XML>
<XMLCHECK />
</ROW>
<ROW>
<ROWID>1</ROWID>
<ID>Съкредитополучател</ID>
<TYPE>48</TYPE>
<TYPEID>2</TYPEID>
<TYPECODE>1</TYPECODE>
<CRSCODE>123123</CRSCODE>
<EGN />
<NAME />
<XML>
<SADL1>
<OwnerCrsCode />
<TABLEVALUE />
</SADL1>
</XML>
<XMLCHECK />
</ROW>
</TABLEVALUE>
</CUSTOMER_SADLS>
</VKRSADL>
Comparing it to the First() gives me only the first ROWID, and there can be multiple. How can I compare the repeater rowid it to each of the ROWID's I've got saved?
I've tried this:
foreach (var child in Xmld.Root.Element("REQUEST").Element("VKRSADL").Element("CUSTOMER_SADLS").Element("TABLEVALUE").Elements("ROW").Elements()) {
//DO SOMETHING
}
but I get an error:
An exception of type 'System.NullReferenceException' occurred in App_Web_f2rvuyke.dll but was not handled in user code
Additional information: Object reference not set to an instance of an object.
As I understand from your question, you want to iterate through ROW element to get all elements which their ROWID is equal to a certain value.
You can use below code to get all ROW elements, then you can do what ever you want with each ROW, in my example below I print ROWID to console window:
string xml = "<VKRSADL><CUSTOMER_SADLS><TABLEVALUE><ROW><ROWID>0</ROWID><ID>Съкредитополучател</ID><TYPE>48</TYPE><TYPEID>1</TYPEID><TYPECODE>1</TYPECODE><CRSCODE>777</CRSCODE><EGN /><NAME /><XML><SADL0><OwnerCrsCode /><TABLEVALUE /></SADL0></XML><XMLCHECK /></ROW><ROW><ROWID>1</ROWID><ID>Съкредитополучател</ID><TYPE>48</TYPE><TYPEID>2</TYPEID><TYPECODE>1</TYPECODE><CRSCODE>123123</CRSCODE><EGN /><NAME /><XML><SADL1><OwnerCrsCode /><TABLEVALUE /></SADL1></XML><XMLCHECK /></ROW></TABLEVALUE></CUSTOMER_SADLS></VKRSADL>";
XDocument xDoc = XDocument.Parse(xml);
foreach (var child in xDoc.Element("VKRSADL").Element("CUSTOMER_SADLS").Element("TABLEVALUE").Elements().Where(e => e.Name == "ROW"))
{
Console.WriteLine(child.Element("ROWID").Value);
}
Note: Above example assume that the XML schema will not be changed, and if it changed then an exception could be occurred.
Try following :
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("ROW").Select(x => new {
rowID = (int)x.Element("ROWID"),
id = (string)x.Element("ID"),
type = (int)x.Element("TYPE"),
typeID = (int)x.Element("TYPEID"),
typeCode = (int)x.Element("TYPECODE"),
crsCode = (int)x.Element("CRSCODE"),
}).ToList();
}
}
}
Related
I'm trying to use LINQ to parse data from an XML file, but the code I have does not seem to work and I cannot figure out what I'm doing wrong.
Shortened version of the xml:
<Components>
....
<Component Id="b3d06054-6113-4775-9353-f48aa21295e8" ProductId="ERDDMR">
<Sections>
<ComponentSection Id="bb05507e-200d-494a-9aef-3181c039efc7" ProductSectionId="ERDDMR.Process" />
<ComponentSection Id="391aead4-cfeb-4739-b8ec-c6b12664189f" ProductSectionId="ERDDMR.Exhaust" />
</Sections>
<VariantData Type="eContact">
<Row Name="dampersize" Value="5610" Description="Return Damper Size" />
<Row Name="damperactuators" Value="1" Description="Return (0=None, 1=2-Pos, 2=MOD)" />
<Row Name="damperconstruction" Value="1" Description="Return (0=N/A, 1=VCD-23, 2=VCD-34" />
</VariantData>
</Component>
<Component Id="f4130a92-aac1-4039-a4df-83d6994ae095" ProductId="ERDSIC">
<Sections>
<ComponentSection Id="1e65f0c4-db4f-4eb7-8605-e37f9d7e6f68" ProductSectionId="ERDSIC.1" />
</Sections>
<VariantData Type="eContact">
<!-- *** Find this one, below! *** -->
<Row Name="dampersize" Value="5926" Description="MUA Damper Size" />
<Row Name="damperactuators" Value="1" Description="MUA (0=None, 1=2-Pos, 2=MOD)" />
<Row Name="damperconstruction" Value="1" Description="MUA (0=N/A, 1=VCD-23, 2=VCD-34, 3=VCD-40" />
</VariantData>
</Component>
...
</Components>
I'm trying to find the attribute Value of the Row Element that has attribute Name = "dampersize" and is a descendant of the Element "Component" whose attribute ProductId = "ERDSIC" (I identified it in the xml above)
My failed attempt is here:
var prop = xDoc.Elements("Component")
.Where(c => c.Attribute("ProductId").Value == "ERDSIC")
.Descendants("Row").Where(t => t.Attribute("Name").Value == "dampersize")
.Select(v => v.Attribute("Value").Value).FirstOrDefault();
Console.WriteLine("Result: " + prop.ToString());
The error I get is (located on the Console.WriteLine line):
System.NullReferenceException: Object reference not set to an instance of an object
EDIT - Changed "Type" to "Name" the code is still wrong
If xDoc is XDocument type:
var xDoc = XDocument.Load("test.xml");
then use the Root property:
var prop = xDoc.Root.Elements("Component")
Or change the xDoc type to XElement:
var xDoc = XElement.Load("test.xml");
Then your code will be fully working.
I suggest you cast to get value instead of use the Value property to avoid this kind of error, I think there is a node that doesn't have the attribute or you misspelled some name,
var prop = xDoc.Root.Elements("Component")
.Where(c => (string)c.Attribute("ProductId") == "ERDSIC")
.Descendants("Row").Where(t => (string)t.Attribute("Name") == "dampersize")
.Select(v => (string)v.Attribute("Value")).FirstOrDefault();
If I put the OP's XML in a file called Data.xml in the \bin\Debug folder and run the following, it works, so I can only assume that his method for loading the XML is not working and prop is null.
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Work
{
public class Program
{
public static void Main(string[] _)
{
var folder = AppDomain.CurrentDomain.BaseDirectory;
var path = Path.Combine(folder, "Data.xml");
var xml = XElement.Load(path);
var prop = xml.Elements("Component")
.Where(c => c.Attribute("ProductId").Value == "ERDSIC")
.Descendants("Row").Where(t => t.Attribute("Name").Value == "dampersize")
.Select(v => v.Attribute("Value").Value).FirstOrDefault();
Console.WriteLine("Result: " + prop);
Console.ReadKey();
}
}
}
I have an xml file with the following format that I'm trying to parse with C# Linq to XML. The problem is that it has this separate metadata element which is the only thing identifying the values below. Is there a good way to do this? I don't have any power to change the format of this file.
<?xml version="1.0" encoding="utf-8?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="Address Line 1" type="xs:string" length="512"/>
<item name="Address Line 2" type="xs:string" length="512"/>
<item name="Date Of Birth" type="xs:dateTime"/>
</metadata>
<data>
<row>
<value>123 Main St</value>
<value xs:nil="true" />
<value>1970-01-01T00:00:00</value>
</row>
<row>
<value>125 Main St</value>
<value>Apt 1</value>
<value>1980-01-01T00:00:00</value>
</row>
</data>
</dataset>
The actual file has about 30 item and corresponding value elements in each row and several hundred row elements following this format. I'm basically looking for the best way to match up the metadata to the values. If Linq to XML is not the best way to achieve this, I'm open to other suggestions that work with C# and .NET 4.5.
I tried just collecting the metadata items in a list and using indices to match them to the values, but it seems to build the list in an arbitrary order, so I'm not sure I can rely on that ordering to identify the values.
XDocument xdoc = XDocument.Load(#"Export.xml");
XNamespace xns = "http://developer.cognos.com/schemas/xmldata/1/";
var metadataQuery = from t in xdoc.Descendants(xns + "item") select t;
List<XElement> metadata = metadataQuery.ToList(); // This list appears to be ordered randomly
The order of elements is always the same, in the order in which they appear in the xml file.
var xdoc = XDocument.Load(#"Export.xml");
XNamespace xns = "http://developer.cognos.com/schemas/xmldata/1/";
var metadata = xdoc.Descendants(xns + "item").ToList();
var data = xdoc.Descendants(xns + "row").ToList();
foreach (var datum in data)
{
var values = datum.Elements(xns + "value").ToList();
for (int i = 0; i < values.Count; i++)
{
Console.WriteLine(metadata[i].Attribute("name").Value + ": " + values[i].Value);
}
Console.WriteLine();
}
Here is a simple method to parse file
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);
XElement dataset = (XElement)doc.FirstNode;
XNamespace ns = dataset.Name.Namespace;
var results = doc.Descendants(ns + "row").Select(x => new {
firstAddr = (string)x.Elements(ns + "value").FirstOrDefault(),
secondAddr = (string)x.Elements(ns + "value").Skip(1).FirstOrDefault(),
dob = (DateTime)x.Elements(ns + "value").Skip(2).FirstOrDefault()
}).ToList();
}
}
}
I have an XML document (without attributes) that is setup like this:
<variables>
<variable>
<name>Name_Value</name>
<value>Value of Entry</value>
</variable>
<variable>
<name>Name_Value2</name>
<value>Value of Entry2</value>
</variable>
</variables>
I have used LINQ to XML to get a list of all the <name> values in the document. These name values are displayed in a listbox control in alphabetical order (which is not the order of the names in the XML document).
When an item is selected in the listbox, I want to pass the name of the item to a method that will search the XML document for that value within the <name> node. Once found, I want to find the next node (i.e., the <value> node) and return it's value as a string.
I've tried all sorts of things to get this information, but apparently I don't know enough about LINQ to XML to get this work. Can only provide a solution for this?
XDocument xdoc = XDocument.Load(path_to_xml);
var query = from v in xdoc.Descendants("variable")
where (string)v.Element("name") == name
select (string)v.Element("value");
This Linq query will return IEnumerbale<string> of value elements, which matched your name. If you sure there should be no more than one variable with specified name
string value = query.SingleOrDefault();
Or in single query:
string value = xdoc.Descendants("variable")
.Where(v => (string)v.Element("name") == name)
.Select(v => (string)v.Element("value"))
.SingleOrDefault();
I think an approache that uses XPath is easier to read :
using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml;
using System.Xml.XPath;
public class Test
{
public static void Main()
{
var xml = XElement.Parse(#"<variables>
<variable>
<name>Name_Value</name>
<value>Value of Entry</value>
</variable>
<variable>
<name>Name_Value2</name>
<value>Value of Entry2</value>
</variable>
</variables>");
Console.WriteLine(
GetVariableValue(xml, "Name_Value")
);
Console.WriteLine(
GetVariableValue(xml, "Name_Value2")
);
}
public static string GetVariableValue(XElement xml, string variableName)
{
return xml.XPathSelectElement("variables/variable[name='" + variableName + "']/value").Value;
}
}
I am trying to bind XML data to Dropdownlist
XElement xDoc = XElement.Parse(QContent.OuterXml);
Here is what my xDoc contains
<root xmlns="">
<item value="-1" text="Select" />
<item value="1" text="$30,000" />
<item value="2" text="$50,000" />
</root>
Query to extract the data into a Listitem :
var query = from xEle in xDoc.Descendants("root")
select new ListItem(xEle.Attribute("value").Value , xEle.Attribute("text").Value);
This yields no results. Please advice.
Thanks in advance
BB
Put your XML file inside App_Data or anywhere in program and in MapPath.
Assign their path and also assign the name of your first XML column in the last line.
Here I'm using "code" because it is my first XML column and country is the name of the column I want to show in my dropdownlist.
private void BindCountry()
{
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("~//App_Data//countries.xml"));
foreach (XmlNode node in doc.SelectNodes("//country"))
{
ddlcountry.Items.Add(new ListItem(node.InnerText, node.Attributes["code"].InnerText));
}
}
You can change your LINQ query to the following which will return all the nodes under root and return new items with the value/text pairs that you are trying to bind to.
var query = from xEle in xDoc.Descendants()
select new {value = xEle.Attribute("value").Value , text = xEle.Attribute("text").Value};
Then set up your bindings as follows including collapsing the query to a list.
ddlList.DataValueField = "value";
ddlList.DataTextField = "text";
ddlList.DataSource = query.ToList();
ddlList.DataBind();
I have an XDocument object. I want to query for elements with a particular name at any depth using LINQ.
When I use Descendants("element_name"), I only get elements that are direct children of the current level. I'm looking for the equivalent of "//element_name" in XPath...should I just use XPath, or is there a way to do it using LINQ methods?
Descendants should work absolutely fine. Here's an example:
using System;
using System.Xml.Linq;
class Test
{
static void Main()
{
string xml = #"
<root>
<child id='1'/>
<child id='2'>
<grandchild id='3' />
<grandchild id='4' />
</child>
</root>";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants("grandchild"))
{
Console.WriteLine(element);
}
}
}
Results:
<grandchild id="3" />
<grandchild id="4" />
An example indicating the namespace:
String TheDocumentContent =
#"
<TheNamespace:root xmlns:TheNamespace = 'http://www.w3.org/2001/XMLSchema' >
<TheNamespace:GrandParent>
<TheNamespace:Parent>
<TheNamespace:Child theName = 'Fred' />
<TheNamespace:Child theName = 'Gabi' />
<TheNamespace:Child theName = 'George'/>
<TheNamespace:Child theName = 'Grace' />
<TheNamespace:Child theName = 'Sam' />
</TheNamespace:Parent>
</TheNamespace:GrandParent>
</TheNamespace:root>
";
XDocument TheDocument = XDocument.Parse( TheDocumentContent );
//Example 1:
var TheElements1 =
from
AnyElement
in
TheDocument.Descendants( "{http://www.w3.org/2001/XMLSchema}Child" )
select
AnyElement;
ResultsTxt.AppendText( TheElements1.Count().ToString() );
//Example 2:
var TheElements2 =
from
AnyElement
in
TheDocument.Descendants( "{http://www.w3.org/2001/XMLSchema}Child" )
where
AnyElement.Attribute( "theName" ).Value.StartsWith( "G" )
select
AnyElement;
foreach ( XElement CurrentElement in TheElements2 )
{
ResultsTxt.AppendText( "\r\n" + CurrentElement.Attribute( "theName" ).Value );
}
You can do it this way:
xml.Descendants().Where(p => p.Name.LocalName == "Name of the node to find")
where xml is a XDocument.
Be aware that the property Name returns an object that has a LocalName and a Namespace. That's why you have to use Name.LocalName if you want to compare by name.
Descendants will do exactly what you need, but be sure that you have included a namespace name together with element's name. If you omit it, you will probably get an empty list.
There are two ways to accomplish this,
LINQ to XML
XPath
The following are samples of using these approaches,
List<XElement> result = doc.Root.Element("emails").Elements("emailAddress").ToList();
If you use XPath, you need to do some manipulation with the IEnumerable:
IEnumerable<XElement> mails = ((IEnumerable)doc.XPathEvaluate("/emails/emailAddress")).Cast<XElement>();
Note that
var res = doc.XPathEvaluate("/emails/emailAddress");
results either a null pointer, or no results.
I am using XPathSelectElements extension method which works in the same way to XmlDocument.SelectNodes method:
using System;
using System.Xml.Linq;
using System.Xml.XPath; // for XPathSelectElements
namespace testconsoleApp
{
class Program
{
static void Main(string[] args)
{
XDocument xdoc = XDocument.Parse(
#"<root>
<child>
<name>john</name>
</child>
<child>
<name>fred</name>
</child>
<child>
<name>mark</name>
</child>
</root>");
foreach (var childElem in xdoc.XPathSelectElements("//child"))
{
string childName = childElem.Element("name").Value;
Console.WriteLine(childName);
}
}
}
}
Following #Francisco Goldenstein answer, I wrote an extension method
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Mediatel.Framework
{
public static class XDocumentHelper
{
public static IEnumerable<XElement> DescendantElements(this XDocument xDocument, string nodeName)
{
return xDocument.Descendants().Where(p => p.Name.LocalName == nodeName);
}
}
}
This my variant of the solution based on LINQ and the Descendants method of the XDocument class
using System;
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
XDocument xml = XDocument.Parse(#"
<root>
<child id='1'/>
<child id='2'>
<subChild id='3'>
<extChild id='5' />
<extChild id='6' />
</subChild>
<subChild id='4'>
<extChild id='7' />
</subChild>
</child>
</root>");
xml.Descendants().Where(p => p.Name.LocalName == "extChild")
.ToList()
.ForEach(e => Console.WriteLine(e));
Console.ReadLine();
}
}
Results:
For more details on the Desendants method take a look here.
We know the above is true. Jon is never wrong; real life wishes can go a little further.
<ota:OTA_AirAvailRQ
xmlns:ota="http://www.opentravel.org/OTA/2003/05" EchoToken="740" Target=" Test" TimeStamp="2012-07-19T14:42:55.198Z" Version="1.1">
<ota:OriginDestinationInformation>
<ota:DepartureDateTime>2012-07-20T00:00:00Z</ota:DepartureDateTime>
</ota:OriginDestinationInformation>
</ota:OTA_AirAvailRQ>
For example, usually the problem is, how can we get EchoToken in the above XML document? Or how to blur the element with the name attribute.
You can find them by accessing with the namespace and the name like below
doc.Descendants().Where(p => p.Name.LocalName == "OTA_AirAvailRQ").Attributes("EchoToken").FirstOrDefault().Value
You can find it by the attribute content value, like this one.
(Code and Instructions is for C# and may need to be slightly altered for other languages)
This example works perfect if you want to read from a Parent Node that has many children, for example look at the following XML;
<?xml version="1.0" encoding="UTF-8"?>
<emails>
<emailAddress>jdoe#set.ca</emailAddress>
<emailAddress>jsmith#hit.ca</emailAddress>
<emailAddress>rgreen#set_ig.ca</emailAddress>
</emails>
Now with this code below (keeping in mind that the XML File is stored in resources (See the links at end of snippet for help on resources) You can obtain each email address within the "emails" tag.
XDocument doc = XDocument.Parse(Properties.Resources.EmailAddresses);
var emailAddresses = (from emails in doc.Descendants("emailAddress")
select emails.Value);
foreach (var email in emailAddresses)
{
//Comment out if using WPF or Windows Form project
Console.WriteLine(email.ToString());
//Remove comment if using WPF or Windows Form project
//MessageBox.Show(email.ToString());
}
Results
jdoe#set.ca
jsmith#hit.ca
rgreen#set_ig.ca
Note: For Console Application and WPF or Windows Forms you must add the "using System.Xml.Linq;" Using directive at the top of your project, for Console you will also need to add a reference to this namespace before adding the Using directive. Also for Console there will be no Resource file by default under the "Properties folder" so you have to manually add the Resource file. The MSDN articles below, explain this in detail.
Adding and Editing Resources
How to: Add or Remove Resources