I have a complex xml and I need to get all the elements
<sdnEntry> containing the value "Individual" in the tag <sdnType>
this is my XML:
string list = #"<?xml version='1.0' standalone='yes'?>
<sdnList xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://tempuri.org/sdnList.xsd'>
<sdnEntry>
<uid>36</uid>
<lastName>AEROCARIBBEAN</lastName>
<sdnType>Entity</sdnType>
<programList>
<program>CUBA</program>
</programList>
</sdnEntry>
<sdnEntry>
<uid>173</uid>
<lastName>ANGLO-CARIBBEAN</lastName>
<sdnType>Entity</sdnType>
<programList>
<program>CUBA</program>
</programList>
</sdnEntry>
<sdnEntry>
<uid>2681</uid>>
<title>NAME1 SURNNAME1</title>
<sdnType>Individual</sdnType>
<programList>
<program>SDGT</program>
</programList>
</sdnEntry>
<sdnEntry>
<uid>2682</uid>
<title>NAME2 SURNNAME2</title>
<sdnType>Individual</sdnType>
<programList>
<program>SDGT</program>
</programList>
<idList>
<id>
<uid>1002</uid>
<idType>Passport</idType>
<idNumber>304555</idNumber>
<idCountry>Egypt</idCountry>
</id>
</idList>
</sdnEntry>
</sdnList>";
I have tried this so far, but it is not working:
listXML.LoadXml(list);
XDocument sndList = XDocument.Parse(listXML.OuterXml);
var nls = XNamespace.Get("http://tempuri.org/sdnList.xsd");
//TEST 1
//--------------------------------------------------------------
var individ = sndList.Elements(nls + "sdnEntry")
.SelectMany(r => r.Descendants("sdnType").Where(e => (string)e.Element("sdnType").Value == "Individual"));
//TEST 2
//--------------------------------------------------------------
IEnumerable<XElement> individuals = from element in sndList.Root.Elements(nls + "sdnEntry")
where (string)element.Element("sdnType") == "Individual"
select element;
what am I doing wrong?
Thanks for helping.
Use this:
var individualNodes = sndList.Root.Elements(nls + "sdnEntry")
.Where(e => e.Element(nls + "sdnType").Value == "Individual");
Related
I am trying to merge two XMLs with same structure but different data into one.
I am getting this error: A node of type Document cannot be added to content.
Below is my code
var productElements =
testGroupProvider.GetTestGroup().ProductTests.Select(
productTest => new XElement(xNamespace + "Product",
new XElement(xNamespace + "ExternalId", productTest.ProductNameKey),
new XElement(xNamespace + "Name", testGroupProvider.GetProductName(productTest)),
new XElement(xNamespace + "ImageUrl", ChoiceBaseHostName + GetProductImageUrl(productTest, TargetDatabase))));
var root = new XDocument(
new XElement(xNamespace + "Feed",
new XAttribute("xmlns", xNamespace),
new XAttribute("name", BVFeedsName),
new XAttribute("incremental", "true"),
new XAttribute("extractDate", DateTime.Now.ToString("o")),
new XElement(xNamespace + "Categories",
new XElement(xNamespace + "Category",
new XElement(xNamespace + "ExternalId", testGroupProvider.GetProductGroup().Id),
new XElement(xNamespace + "Name", testGroupProvider.GetProductGroup().Name),
testGroupProvider.GetTestGroup().Name),
new XElement(xNamespace + "Products", productElements)));
var filePath = #"D:\testXML\test.xml";
XElement xml = XElement.Load(filePath);
xml.Add(root);
xml.Save(filePath);
Can anyone tell me what i am doing wrong.
This is the XML structure in test.xml
<?xml version="1.0" encoding="utf-8"?>
<Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
<Categories>
<Category>
<ExternalId>{09B3B4FB-F5CF-4522-BE96-4C4B535580C3}</ExternalId>
<Name>Cereal and muesli</Name>
</Category>
</Categories>
<Products>
<Product>
<ExternalId>coles-almond-hazelnut-macadamia-cluster-fusions</ExternalId>
<Name>Coles Almond, Hazelnut & Macadamia Cluster Fusions</Name>
<ImageUrl></ImageUrl>
</Product>
</Products>
</Feed>
The second XML has the same structure with different products
<?xml version="1.0" encoding="utf-8"?>
<Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
<Categories>
<Category>
<ExternalId>{12}</ExternalId>
<Name>cat1</Name>
</Category>
</Categories>
<Products>
<Product>
<ExternalId>Id</ExternalId>
<Name>Ccoles</Name>
<ImageUrl></ImageUrl>
</Product>
</Products>
</Feed>
I want to combine them like below
<?xml version="1.0" encoding="utf-8"?>
<Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
<Categories>
<Category>
<ExternalId>{09B3B4FB-F5CF-4522-BE96-4C4B535580C3}</ExternalId>
<Name>Cereal and muesli</Name>
</Category>
<Category>
<ExternalId>{12}</ExternalId>
<Name>cat1</Name>
</Category>
</Categories>
<Products>
<Product>
<ExternalId>coles-almond-hazelnut-macadamia-cluster-fusions</ExternalId>
<Name>Coles Almond, Hazelnut & Macadamia Cluster Fusions</Name>
<ImageUrl></ImageUrl>
</Product>
<Product>
<ExternalId>Id</ExternalId>
<Name>Ccoles</Name>
<ImageUrl></ImageUrl>
</Product>
</Products>
</Feed>
A xml document must have only one root.
Working with the documents you attached, you can replace the xml.Add(root); with the following (i.e. it will add each node under one root to the other xml root)
foreach (var child in root.Root.Elements())
{
xml.Element(child.Name.ToString()).Add(child.Nodes());
}
Edit - A further generalization
You can generalize the above code using a Merge extension of 2 XElements so that it reads as follows
foreach (var child in root.Elements())
{
xml.Element(child.Name.ToString()).Merge(child, xNamespace + "ExternalId");
}
Having defined the extension
public static void Merge(this XElement root1, XElement root2, XName element_id)
{
root1.Add(root2.Elements().Except(root1.Elements(), new MyComparer(element_id)));
}
with a xml comparer
public class MyComparer : IEqualityComparer<XElement>
{
private XName _element_id;
public MyComparer(XName element_id)
{
_element_id = element_id;
}
public bool Equals(XElement x, XElement y)
{
return x.Element(_element_id).Value.Equals(y.Element(_element_id).Value);
}
public int GetHashCode(XElement el)
{
return el.Element(_element_id).Value.GetHashCode();
}
}
Select correct nodes to add and correct nodes to be added.
var filePath = #"D:\testXML\test.xml";
XElement xml = XElement.Load(filePath);
var xmlCategories = xml.Descendants("Categories").First();
var rootCategories = root.Descendants("Category");
xmlCategories.Add(rootCategories);
var xmlProducts = xml.Descendants("Products").First();
var rootProducts = root.Descendants("Product");
xmlProducts.Add(rootProducts);
xml.Save(filePath);
Be crystal clear what you are doing.
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication2
{
class Program
{
const string FILENAME1 = #"c:\temp\test1.xml";
const string FILENAME2 = #"c:\temp\test2.xml";
static void Main(string[] args)
{
XDocument doc1 = XDocument.Load(FILENAME1);
XDocument doc2 = XDocument.Load(FILENAME2);
XElement category1 = doc1.Descendants().Where(x => x.Name.LocalName == "Categories").FirstOrDefault();
XElement category2 = doc2.Descendants().Where(x => x.Name.LocalName == "Categories").FirstOrDefault();
category1.Add(category2.Descendants());
XElement product1 = doc1.Descendants().Where(x => x.Name.LocalName == "Products").FirstOrDefault();
XElement product2 = doc2.Descendants().Where(x => x.Name.LocalName == "Products").FirstOrDefault();
product1.Add(product2.Descendants());
}
}
}
Try this, sorry about the VB
'second is The second XML has the same structure with different products
Dim combined As XElement = New XElement(test) 'create copy of test.xml
combined.<Categories>.LastOrDefault.Add(second.<Categories>.Elements)
combined.<Products>.LastOrDefault.Add(second.<Products>.Elements)
or
'if test can be used to combine then
test.<Categories>.LastOrDefault.Add(second.<Categories>.Elements)
test.<Products>.LastOrDefault.Add(second.<Products>.Elements)
The result is
<Feed name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00" xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6">
<Categories>
<Category>
<ExternalId>{09B3B4FB-F5CF-4522-BE96-4C4B535580C3}</ExternalId>
<Name>Cereal and muesli</Name>
</Category>
<Category>
<ExternalId>{12}</ExternalId>
<Name>cat1</Name>
</Category>
</Categories>
<Products>
<Product>
<ExternalId>coles-almond-hazelnut-macadamia-cluster-fusions</ExternalId>
<Name>Coles Almond, Hazelnut & Macadamia Cluster Fusions</Name>
<ImageUrl></ImageUrl>
</Product>
<Product>
<ExternalId>Id</ExternalId>
<Name>Ccoles</Name>
<ImageUrl></ImageUrl>
</Product>
</Products>
</Feed>
The test data I used is
Dim test As XElement =
<Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
<Categories>
<Category>
<ExternalId>{09B3B4FB-F5CF-4522-BE96-4C4B535580C3}</ExternalId>
<Name>Cereal and muesli</Name>
</Category>
</Categories>
<Products>
<Product>
<ExternalId>coles-almond-hazelnut-macadamia-cluster-fusions</ExternalId>
<Name>Coles Almond, Hazelnut & Macadamia Cluster Fusions</Name>
<ImageUrl></ImageUrl>
</Product>
</Products>
</Feed>
Dim second As XElement =
<Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
<Categories>
<Category>
<ExternalId>{12}</ExternalId>
<Name>cat1</Name>
</Category>
</Categories>
<Products>
<Product>
<ExternalId>Id</ExternalId>
<Name>Ccoles</Name>
<ImageUrl></ImageUrl>
</Product>
</Products>
</Feed>
The XElements can be loaded like this
test = XElement.Load("PATH")
second = XElement.Load("second PATH")
and saved like this
test.Save("PATH")
second.Save("second PATH")
combined.Save("combined PATH")
I want get Order Lines for each Order and bring them to an EMail Body as Table like
Value 1 | Value 2 | Value 3
12345 ABC X1_
XML Code:
<?xml version="1.0" encoding="utf-8"?><UniversalInterchange xmlns= "http://www.designworker/namespace" version="1.1">
<Header> </Header>
<Body>
<UniversalShipment xmlns="http://www.designworker/namespace" version="1.1">
<Shipment>
<DataContext>
<DataTargetCollection>
<DataTarget>
<Type>SMTPTYPE</Type>
</DataTarget>
</DataTargetCollection>
</DataContext>
<Order>
<OrderNumber>99348234234</OrderNumber>
<OrderLineCollection>
<OrderLine>
<LineNumber>1</LineNumber>
<OrderedQty>455.000</OrderedQty>
<OrderedQtyUnit>
<Code>MORE</Code>
</OrderedQtyUnit>
<Product>
<Code>999LAM01</Code>
<Description>New Design Work</Description>
</Product>
<QuantityMet>1.000</QuantityMet>
<ShortfallQuantity>0</ShortfallQuantity>
</OrderLine>
<OrderLine>
<LineNumber>2</LineNumber>
<OrderedQty>655.000</OrderedQty>
<OrderedQtyUnit>
<Code>SOME</Code>
</OrderedQtyUnit>
<Product>
<Code>999LAM02</Code>
<Description>OLD Design Work </Description>
</Product>
<QuantityMet>3.000</QuantityMet>
<ShortfallQuantity>45</ShortfallQuantity>
</OrderLine>
</OrderLineCollection>
</Order>
</Shipment>
</UniversalShipment>
</Body>
</UniversalInterchange>
I have tried to solve this with this code:
var xDoc = XDocument.Parse(xmlValue);
XNamespace nsp = ns;
try
{
var value = xDoc
.Element(nsp + "UniversalInterchange")
.Element(nsp + "Body")
.Element(nsp + "UniversalShipment")
.Element(nsp + "Order")
.Element(nsp + "OrderLine")
.Element(nsp + "LineNumber")
.Value;
return value;
But when I have more than one Line in the Order it won't work.
How can I solve this on a better way ?
Looks like the navigation path is missing a few .Element()-calls.
var orderLines = xDoc
.Element(nsp + "UniversalInterchange")
.Element(nsp + "Body")
.Element(nsp + "UniversalShipment")
.Element(nsp + "Shipment")
.Element(nsp + "Order")
.Element(nsp + "OrderLineCollection")
.Elements(nsp + "OrderLine");
// 1, 2
var lineNumbers = orderLines.Select(x => x.Element(nsp + "LineNumber").Value);
Whenever an element isn't found, null is returned from .Element(). You should also use .Elements() instead of .Element() if you expect multiple entries.
I have an XML looking like this :
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ocrsdk.com/schema/resultDescription-1.0.xsd http://ocrsdk.com/schema/resultDescription-1.0.xsd" xmlns="http://ocrsdk.com/schema/resultDescription-1.0.xsd">
<page index="0">
<text id="print" left="160" top="349" right="339" bottom="384">
**<value>Vertraqsnummer:</value>**
<line left="167" top="366" right="326" bottom="384">
<char left="167" top="366" right="180" bottom="382">V</char>
<char left="287" top="370" right="302" bottom="382">
<charRecVariants>
<variant charConfidence="22">m</variant>
<variant charConfidence="-1">rn</variant>
</charRecVariants>m</char>
<char left="304" top="370" right="314" bottom="382">e</char>
<char left="316" top="370" right="322" bottom="382">r</char>
<char left="324" top="370" right="326" bottom="382" suspicious="true">:</char>
</line>
</text>
<text id="handprint" left="387" top="1035" right="635" bottom="1089">
**<value>309.05</value>**
<line left="398" top="1045" right="633" bottom="1089">
<char left="398" top="1052" right="426" bottom="1088">3</char>
<char left="423" top="1061" right="455" bottom="1089" suspicious="true">0</char>
<char left="546" top="1045" right="633" bottom="1089" suspicious="true">5</char>
</line>
</text>
<checkmark id="checked" left="883" top="427" right="928" bottom="469">
**<value>checked</value>**
</checkmark>
<checkmark id="not checked" left="884" top="511" right="928" bottom="554">
**<value>unchecked</value>**
</checkmark>
<barcode id="leftBarcode" left="46" top="1048" right="128" bottom="1350">
<value encoding="Base64">QkYxMDExNQ==</value>
</barcode>
I want to be able to parse only the fields where XXX is written, take the value inside and place it under the field of my c# class.
For example, for this XML, I want to take these values:
**<value>Vertraqsnummer:</value>**
**<value>309.05</value>**
**<value>checked</value>**
using class "A" for example :
class A
{
public string s1;
public string s2;
public string s3;
}
my result should be :
s1 = Vertraqsnummer
s2 = 309.05
s3 = checked
I looked at some questions here but the only thing I noticed is that I can use XsdObjectGen or XSD.exe. The problem is that they take the whole XML and not only the parts I need.
any help would be very appriciated!
XmlNamespaceManager nsMgr = new XmlNamespaceManager(new NameTable());
nsMgr.AddNamespace("ns", "http://ocrsdk.com/schema/resultDescription-1.0.xsd");
var result = XDocument.Load(filename)
.XPathSelectElements("//ns:text/ns:value|//ns:checkmark[#id='checked']/ns:value", nsMgr)
.Select(x => x.Value)
.ToList();
or without XPATH
XNamespace ns = "http://ocrsdk.com/schema/resultDescription-1.0.xsd";
var xDoc = XDocument.Load(filename);
var result = xDoc.Descendants(ns + "text")
.Union(xDoc.Descendants(ns + "checkmark").Where(c => (string)c.Attribute("id") == "checked"))
.Select(x => x.Element(ns + "value").Value)
.ToList();
I'm trying to get all elements with a given value, "John", from an xml document.
Is this possible with LINQ to XML?
What I want to achieve is to replace all "John" values with "Wayne". I know this can easily be done with xslt, but I need to do this by code.
My XML:
<Root>
<Parents>
<Parent>
<Name>John</Name>
<Age>18</Age>
</Parent>
<Parent>
<Name>John</Name>
<Age>25</Age>
</Parent>
<Parent>
<Name>Peter</Name>
<Age>31</Age>
</Parent>
</Parents>
</Root>
I have tried this:
XmlDocument doc = new XmlDocument();
doc.Load(#"C:/Temp/test.xml");
var elements = doc.Elements().Where(w => w.Value == "John");
foreach (var element in elements)
{
element.Value = "Wayne";
}
You may use System.Xml.Linq.XDocument. It's more easy to work with.
XDocument doc = XDocument.Load(your file path);
var elements = doc.Descendants("Name").Where(i => i.Value == "John");
foreach (var element in elements)
{
element.Value = "Wayne";
}
doc.Save(your save file path);
Here is the output:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Parents>
<Parent>
<Name>Wayne</Name>
<Age>18</Age>
</Parent>
<Parent>
<Name>Wayne</Name>
<Age>25</Age>
</Parent>
<Parent>
<Name>Peter</Name>
<Age>31</Age>
</Parent>
</Parents>
</Root>
Here is an approach that will get all elements with the value John, regardless of what element (although only at the same level; you'd have to modify it to look at different levels too; you could use the Descendants approach described previously):
XDocument doc = XDocument.Load(#"C:\temp\test.xml");
var ns = doc.Root.GetDefaultNamespace();
var elements = doc.Element(ns + "Root").Element(ns + "Parents").Elements(ns + "Parent").Elements().Where(w => w.Value == "John");
foreach (var element in elements)
{
element.Value = "Wayne";
}
var stream = new FileStream(#"C:\temp\test.xml", FileMode.Create);
doc.Save(stream);
I've got xml that looks like what I have below. I can read the title but am having trouble getting to the url of media:content. Any suggestions? My non-working c# is below along with the xml.
XNamespace xmlns = "http://www.w3.org/2005/Atom";
var names =
(from data in XDocument.Load("http://channel9.msdn.com/Events/Build/2012/rss").Descendants("item")
let xElement = data.Element("title")
let xElementUrls = data.Element("media")
where xElement != null
select new
{
Title = xElement.Value,
Urls = data.Elements(xmlns + "media:group")
//MediaGroup = data.Element("media:group")
}).ToList();
and the XML:
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:c9="http://channel9.msdn.com">
<channel>
<item>
<title>Building Windows 8 LOB Apps (Repeat)</title>
<media:group>
<media:content url="http://video.ch9.ms/sessions/build/2012/2-104R.mp4"
expression="full" duration="0" fileSize="1" type="video/mp4" medium="video"/>
<media:content url="http://video.ch9.ms/sessions/build/2012/2-104R.wmv"
expression="full" duration="0" fileSize="1" type="video/x-ms-wmv" medium="video"/>
</media:group>
</item>
<item>
<item>
...
</item>
Added this based on L.B.'s suggestion but I can't figure out how to get url's out (it is now returning a list of URL's per item as expected.
var items = xDoc.Descendants("item")
.Where(g => g.Element(media + "group") != null)
.Select(g => new {
Title = g.Element("title").Value,
Url = g.Element(media + "group")
.Element(media + "content")
.Attribute("url").Value
})
.ToList();
var xDoc = XDocument.Load("http://channel9.msdn.com/Events/Build/2012/rss");
XNamespace media = "http://search.yahoo.com/mrss/";
var items = xDoc.Descendants("item")
.Where(g => g.Element(media + "group") != null)
.Select(g => new {
Title = g.Element("title").Value,
Url = g.Element(media + "group")
.Element(media + "content")
.Attribute("url").Value
})
.ToList();
media is a namespace alias, not an element.
You need to get the group element within the http://search.yahoo.com/mrss/ namespace:
XNamespace m = "http://search.yahoo.com/mrss/";
let xElementUrls = data.Element(m + "group")
You have the wrong namespace...
XNamespace xmlns = "http://www.w3.org/2005/Atom";
should be
XNamespace xmlns = "http://search.yahoo.com/mrss/";
And you are combining the namespace and element name incorrectly
...
Urls = data.Elements(xmlns + "group")
....