display xml using linq - c#

MessageBox.Show("Hi");
string xml = #"<Table>
<Product>
<Product_id>1</Product_id>
<Product_name>Product 1</Product_name>
<Product_price>1000</Product_price>
</Product>
<Product><Product_id>2</Product_id><Product_name>Product 2</Product_name><Product_price>2000</Product_price></Product>
<Product><Product_id>3</Product_id><Product_name>Product 3</Product_name><Product_price>3000</Product_price></Product>
<Product><Product_id>4</Product_id><Product_name>Product 4</Product_name><Product_price>4000</Product_price></Product>
</Table>";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants("Product_id"))
{
Console.WriteLine(element);
}
Upon button click only Hi MessageBox is displayed. The elements are not displayed.

Please try this. The values will be shown in the console.
MessageBox.Show("Hi");
string xml = #"
<Table>
<Product>
<Product_id>1</Product_id>
<Product_name>Product 1</Product_name>
<Product_price>1000</Product_price>
</Product>
<Product><Product_id>2</Product_id><Product_name>Product 2</Product_name><Product_price>2000</Product_price></Product>
<Product><Product_id>3</Product_id><Product_name>Product 3</Product_name><Product_price>3000</Product_price></Product>
<Product><Product_id>4</Product_id><Product_name>Product 4</Product_name><Product_price>4000</Product_price></Product>
</Table>";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants("Product_id"))
{
Console.WriteLine(element.Value);
}
Console.Read();
You should call Console.WriteLine(element.Value);

Related

C# : XML Parsing : Group XML on a node and then subGroup underneath the same group

<?xml version="1.0" encoding="UTF-8"?>
<Batch Id="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PurchaseOrders>
<PurchaseOrder id="xx267681">
<Header>
<AccountNumber>999</AccountNumber>
<ShipDate>2/10/2009</ShipDate>
</Header>
<PurchaseOrderDetails>
<Item>
<ItemNumber>yy235240</ItemNumber>
<Quantity>200</Quantity>
</Item>
<Item>
<ItemNumber>yy336820</ItemNumber>
<Quantity>3</Quantity>
</Item>
</PurchaseOrderDetails>
</PurchaseOrder>
<PurchaseOrder id="zz267456">
<Header>
<AccountNumber>123</AccountNumber>
<ShipDate>2/10/2009</ShipDate>
</Header>
<PurchaseOrderDetails>
<Item>
<ItemNumber>nn235240</ItemNumber>
<Quantity>200</Quantity>
</Item>
</PurchaseOrderDetails>
</PurchaseOrder>
</PurchaseOrders>
</Batch>
Attached above is the XML file I am trying to parse. My current C# code find all items in the XML file and assigns it against the PO#. But the recent XML file I got to know that there can be multiple PO# in the same XML file and hence I now need to find only those items matching to that PO#.
So in above example, PONumber with xx267681 has 2 items whereas 2nd PO has only item.
Here is what I tried so far.
try
{
ArrayList ItemsInFeed = new ArrayList();
XDocument xDoc = XDocument.Load(fileName);
foreach (var node in xDoc.Descendants("PurchaseOrder"))
{
poID = node.Attribute("id").Value;
}
foreach (var node in xDoc.Descendants("Item"))
{
Items itemRcd = new Items();
itemRcd.ItemNr = node.Descendants("ItemNumber")?.First().Value;
ItemsInFeed.Add(itemRcd);
}
if (ItemsInFeed.Count > 0)
{
// Do other logic based on the items linked to each PO#.
// Issue found : So far each XML file has one PO#, but latest XML file received has more than PO# and underlying items.
ItemsInFeed.Clear();
}
}
catch (Exception ex)
{
//Catch exception here
}
Try following :
XDocument xDoc = XDocument.Load(fileName);
var results = xDoc.Descendants("PurchaseOrder").Select(x => new
{
poID = (string)x.Attribute("id"),
items = x.Descendants("Item").Select(y => new
{
itemNumber = (string)y.Element("ItemNumber"),
quantity = (int)y.Element("Quantity")
}).ToList()
}).ToList();

how to get value of child nodes in xml one by one

How can i read asin and its value from This xml file.
i have multiple product in this xml file.
This two products asin i want to get.
XDocument xdoc = XDocument.Load(#"D:\Product\WriteText2.xml");
XElement match = xdoc.Root.Element("GetMatchingProductForIdResult");
foreach(XElement product in match.Elements("Products"))
{
XElement asin = product.Element("Identifiers").Element("MarketplaceASIN").Element("ASIN");
string asinValue = asin.Value;
}
<GetMatchingProductForIdResult Id="619659000431" IdType="UPC" status="Success">
<Products>
<Product>
<Identifiers>
<MarketplaceASIN>
<MarketplaceId>A21TJRUUN4KGV</MarketplaceId>
<ASIN>B002U1ZBG0</ASIN>
</MarketplaceASIN>
</Identifiers>
</Product>
</Products>
</GetMatchingProductForIdResult>
<GetMatchingProductForIdResult Id="190198462411" IdType="UPC" status="Success">
<Products>
<Product>
<Identifiers>
<MarketplaceASIN>
<MarketplaceId>A21TJRUUN4KGV</MarketplaceId>
<ASIN>B073Q5R6VR</ASIN>
</MarketplaceASIN>
</Identifiers>
</Product>
</Products>
</GetMatchingProductForIdResult>
You can use System.Xml.Linq:
XDocument xdoc = XDocument.Load("file.xml");
XElement match = xdoc.Element("GetMatchingProductForIdResult");
foreach(XElement product in match.Elements("Products")){
XElement asin = product.Element("Identifiers")
.Element("MarketplaceASIN").XElement("ASIN");
string asinValue = asin.Value;
}

Select Next Sibling if Element in previous sibling is a certain value XML

I have the following XML file
<ProdExtract>
<Product>
<Barcode>
<Eancode>0000000000000</Eancode>
</Barcode>
<Barcode>
<Eancode>0000000000000</Eancode>
</Barcode>
<Barcode>
<Eancode>5391524344444</Eancode>
</Barcode>
</Product>
<Product>
<Barcode>
<Eancode>5391524322222</Eancode>
</Barcode>
</Product>
</ProdExtract>
The desired ouput is to get the Eancode of both products.
For the first product, to skip all the zero barcode and select/ouput the next valid Eancode (5391524344444) for that product. For the second product output that valid default Eancode (5391524322222).
By default this is how I am extracting the Eancode for a product that only has one Barcode node
p.q_barcode = node.SelectSingleNode("Barcode/Eancode").FirstChild.InnerText;
Issue is dealing with the product that has multiple invalid zero value Eancodes before extracting the next valid one.
With current code
XmlDocument xDoc = new XmlDocument();
xDoc.Load(data);
XmlElement root = xDoc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("Product");
foreach (XmlNode node in nodes)
{
var noneZeroEancode = xml.Descendants("Eancode").Where(x => x.Value != "0000000000000");
string outputString = eancode.First().Value;
p.q_barcode = outputString;
//other properties....
p.q_description = node.SelectSingleNode("ProductID/LongDescription").InnerText;
//insert record into table
//go read next "Product" node (if any)
}
Output result: on reading the second node, it is assigning value of first Eancode to the second product. So all products that follow have the Eancode value of 5391524344444 instead of their own unique value.
Additional Info (Just for clarity):
This functionality is within a loop that reads each product node, maps the values to table columns and imports the record/product, then moves on to read the next node. This part needs no answer as I have that solved.
Try something like this:
using System;
using System.Linq;
using System.Xml.Linq;
namespace xml {
class Program {
static void Main(string[] args) {
var data =
#"<ProdExtract>
<Product>
<Barcode>
<Eancode>0000000000000</Eancode>
</Barcode>
</Product>
<Product>
<Barcode>
<Eancode>0000000000000</Eancode>
</Barcode>
</Product>
<Product>
<Barcode>
<Eancode>5391524344444</Eancode>
</Barcode>
</Product>
</ProdExtract>";
var xml = XDocument.Parse(data);
var eancode = xml.Descendants("Eancode").Where(x => x.Value != "0000000000000");
var product = eancode.Select(x => x.Parent.Parent);
foreach (var p in product) {
Console.WriteLine(p);
}
}
}
}
The first step is to select elements that don't have the 00...0 Eancode value. Next look at each of the returned nodes (XElements) and get the grandparent.
Possible issue:
If your XML isn't formatted as expected (if 'Eancode' exists but isn't within a 'Product/Barcode') you would not get the expected results, you could even generate an exception getting the parent of the parent.

How to get specific children of a xml element?

I am loading a xml document and I am having a foreach loop in its elements and I want to select child elements named tag in it.
This is the xml file:
<?xml version="1.0" encoding="utf-8"?>
<view>
<tag>
<name>content</name>
<tag>
<name>div</name>
</tag>
</tag>
</view>
And this is the code:
string xmlString = System.IO.File.ReadAllText(HttpContext.Current.Server.MapPath("~/xml/xml.xml"));
XDocument doc = XDocument.Parse(xmlString);
XElement xmlElement = doc.Element("view");
foreach (var tagItem in xmlElement.Descendants("tag"))
{
//do something
}
The code written in foreach loop would contain all of tag elements in any depth, but I want to get the first depth ones(the children).
How to do this with linq?
Assuming the desired elements are always children of the <view> element you can use:
XElement xmlElement = doc.Element("view");
foreach (var tagItem in xmlElement.Elements("tag"))
{
//do something (only direct children)
}
There is nothing more to be done to get the desired elements. You can then however implement your "do something" with Linq, for example:
XElement firstElem = xmlElement.Elements("tag").OrderBy(e => e.Name).First();

Filter XDocument more efficiently

I would like to filter with high performance XML elements from an XML document.
Take for instance this XML file with contacts:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="asistentes.xslt"?>
<contactlist evento="Cena Navidad 2010" empresa="company">
<contact type="1" id="1">
<name>Name1</name>
<email>xxxx#zzzz.es</email>
<confirmado>SI</confirmado>
</contact>
<contact type="1" id="2">
<name>Name2</name>
<email>xxxxxxxxx#zzzze.es</email>
<confirmado>Sin confirmar</confirmado>
</contact>
</contaclist>
My current code to filter from this XML document:
using System;
using System.Xml.Linq;
class Test
{
static void Main()
{
string xml = #" the xml above";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants("contact")) {
Console.WriteLine(element);
var id = element.Attribute("id").Value;
var valor = element.Descendants("confirmado").ToList()[0].Value;
var email = element.Descendants("email").ToList()[0].Value;
var name = element.Descendants("name").ToList()[0].Value;
if (valor.ToString() == "SI") { }
}
}
}
What would be the best way to optimize this code to filter on <confirmado> element content?
var doc = XDocument.Parse(xml);
var query = from contact in doc.Root.Elements("contact")
let confirmado = (string)contact.Element("confirmado")
where confirmado == "SI"
select new
{
Id = (int)contact.Attribute("id"),
Name = (string)contact.Element("name"),
Email = (string)contact.Element("email"),
Valor = confirmado
};
foreach (var contact in query)
{
...
}
Points of interest:
doc.Root.Elements("contact") selects only the <contact> elements in the document root, instead of searching the whole document for <contact> elements.
The XElement.Element method returns the first child element with the given name. No need to convert the child elements to a list and take the first element.
The XElement and XAttribute classes provide a wide selection of convenient conversion operators.
You could use LINQ:
foreach (XElement element in doc.Descendants("contact").Where(c => c.Element("confirmado").Value == "SI"))

Categories