I want to retrieve data from XML(which have also an xsd file) using C#. What can it be wrong with my code:
My Xml file look likes this.
<Model_1 xmlns="http://www.3ds.com/xsd/3DXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.3ds.com/xsd/3DXML ./3DXML.xsd">
<Header>
<item></item>
<item1></item1>
<item2></item2>
</Header>
<Product>
<otheritem></otheritem>
<otheritem1></otheritem1>
<otheritem2></otheritem2>
</Product>
<Books>
<otheritem></otheritem>
<otheritem1></otheritem1>
<otheritem2></otheritem2>
</Books>
</Model_1>
...c#
XDocument xdoc = Document.Load("document.xml") var items = from item in xdoc.Descendants("Header")
select new
{
_Item= item.Element("Item").Value,
_Item1= item.Element("Item1").Value,
_Item2= item.Element("Item2").Value,
};
foreach (var item in items)
{
Item= item._Item;
Item1 = item._Item1;
Item2 = item.Item2;
}
Console.WriteLine("show me :" + Item+ " + " + Item1 + " + " + Item2);
How can I extract just items from Header and not Product or Books?
You need to use namespace:
var ns = xdoc.Root.GetDefaultNamespace();
var header = xdoc.Root.Element(ns + "Header");
Also keep in mind - you have lower case item in your xml, not Item:
Item = (string)header?.Element(ns + "item");
Item1 = (string)header?.Element(ns + "item1");
Item2 = (string)header?.Element(ns + "item2");
Related
I am not able to get the value from this xml response, I will appreciate any help.
<Response>
<Result>
<Item1>GREEN</Item1>
<Item2>05/19/2017 22:08:14</Item2>
</Result>
<Other>
<Id>xxxxxxxxxxxxc</Id>
</Other>
</Response>
What I tried so far but the results is empty
string responseXml = response.ToXML();
XElement doc = XElement.Load(new StringReader(responseXml));
var results = from p in
doc.Descendants("Result")
select new
{
item = p.Element("Item1").Value,
};
foreach (var elm in results)
{
Console.WriteLine(elm.item);
}
Use Parse instead of load. You may also be getting error due to extra characters in the string. In the string you postged there are single quotes. Not sure if the single quote is in the actual string you are using.
string responseXml = "<Response>" +
"<Result>" +
"<Item1>GREEN</Item1>" +
"<Item2>05/19/2017 22:08:14</Item2>" +
"</Result>" +
"<Other>" +
"<Id>xxxxxxxxxxxxc</Id>" +
"</Other>" +
"</Response>";
XElement doc = XElement.Parse(responseXml);
var results = from p in
doc.Descendants("Result")
select new
{
item = p.Element("Item1").Value,
};
foreach (var elm in results)
{
Console.WriteLine(elm.item);
}
I'm working on a C# Desktop App and in a module I display the info of a xml file into a listview, I coded my solution with Linq to XML like this
string path = "prueba.xml";
listView1.Items.Clear();
listView1.Columns.Add(path, 400);
XElement doc = XElement.Load(path);
var result = from persona in doc.Elements("persona")
select new{
nombre = Convert.ToString(persona.Element("nombre").Value).Trim(),
ocupacion = Convert.ToString(persona.Element("ocupacion").Value).Trim()
};
foreach (var persona in result)
{
/*ListViewItem item = new ListViewItem(persona.nombre);
item.SubItems.Add(persona.ocupacion);*/
ListViewItem nombre = new ListViewItem("<nombre> " + persona.nombre + " </nombre>");
ListViewItem ocupacion = new ListViewItem("<ocupacion> " + persona.ocupacion + " </ocupacion>");
listView1.Items.Add("<persona>");
listView1.Items.Add(nombre);
listView1.Items.Add(ocupacion);
listView1.Items.Add("</persona>");
listView1.Items.Add("");
}
}
}
and it works very fine, as you can see there are items in the listview that represents the nodes of the xml file, but those items are specific for this xml file
<?xml version="1.0" encoding="utf-8" ?>
<personas>
<persona>
<nombre>Pablo el primero</nombre>
<ocupacion>Programador Cliente-Servidor</ocupacion>
</persona>
<persona>
<nombre>Pablo el segundo</nombre>
<ocupacion>Programador Web</ocupacion>
</persona>
</personas>
as you can see in the C# code, it fits for the xml file above but if I retrieve another xml file with different nodes name like for example
<juego>
<juegos>
<name id="ac"> God of War III </name>
...
</juegos>
</juego>
my code wont show me the nodes <juegos>...</juegos> because it will still display the <person>...</person> nodes because it was created to display only the node <person>...</person> so my question: is there a way to show the information of a xml file into a listview using Linq to XML and at the same time display the info as it is coded in the xml file?
I want to know if I can display this format in teh listview:
<?xml version="1.0" encoding="utf-8" ?>
<personas>
<persona>
<nombre>Pablo el primero</nombre>
<ocupacion>Programador Cliente-Servidor</ocupacion>
</persona>
<persona>
<nombre>Pablo el segundo</nombre>
<ocupacion>Programador Web</ocupacion>
</persona>
</personas>
You don't have to use linq to do it, you can simply query the elements of your document.
listView1.View = System.Windows.Forms.View.Details;
listView1.AutoArrange = false;
listView1.Alignment = ListViewAlignment.Left;
listView1.Items.Clear();
listView1.Columns.Add("XML",400);
string xml =
#"<?xml version=""1.0"" encoding=""utf-8"" ?>
<personas>
<persona>
<nombre>Pablo el primero</nombre>
<ocupacion>Programador Cliente-Servidor</ocupacion>
</persona>
<persona>
<nombre>Pablo el segundo</nombre>
<ocupacion>Programador Web</ocupacion>
</persona>
</personas>";
XDocument doc = XDocument.Parse(xml);
List<ListViewItem> ItemList = new List<ListViewItem>();
foreach (XElement elem in doc.Elements())
{
AddNewItemToList(ItemList, elem);
}
listView1.Items.AddRange(ItemList.ToArray());
...
private void AddNewItemToList(List<ListViewItem> ItemList, XElement elem)
{
string attributes = "";
if (elem.HasAttributes)
{
foreach (XAttribute attr in elem.Attributes())
{
attributes += " " + attr.Name + "=\"" + attr.Value + "\"";
}
}
if (elem.HasElements)
{
ItemList.Add(new ListViewItem("<" + elem.Name + attributes + ">"));
foreach (XElement childElem in elem.Elements())
{
AddNewItemToList(ItemList, childElem);
}
ItemList.Add(new ListViewItem("</" + elem.Name + ">"));
}
else
{
ItemList.Add(new ListViewItem("<" + elem.Name + attributes + ">" + elem.Value + "</" + elem.Name + ">"));
}
}
I need assistance in retrieving the element Country and Its value 1 in the below code.
Thanks in advance.
<?xml version="1.0" encoding="utf-8"?>
<env:Contentname xmlns:env="http://data.schemas" xmlns="http://2013-02-01/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<env:Content action="Hello">
<env:Data xsi:type="Yellow">
</env:Data>
</env:Content>
<env:Content action="Hello">
<env:Data xsi:type="Red">
<Status xmlns="http://2010-10-10/">
<Id >39681</Id>
<Name>Published</Name>
</Status>
</env:Data>
</env:Content>
<env:Content action="Hello">
<env:Data xsi:type="green">
<Document>
<Country>1</Country>
</Document>
</env:Data>
</env:Content>
</env:Body>
</env:Contentname>
I tried this,
var result = from x in root.Descendants(aw + "Data")
where (string)x.Attribute(kw + "type") == "green"
select x;
foreach (var item in result)
{
var str = item.Element("Document").Element("Country");
Console.WriteLine(str.Value);
}
But i am getting error.(Object reference not set to an instance of an object.)
kindly help me with this.
This is the problem, for two reasons:
var str = item.Element("Document").Element("country");
Firstly, XML is case-sensitive - you want Country, not country.
Secondly, those elements inherit the namespace declared with xmlns=... in the root element. You need:
XNamespace ns = "http://2013-02-01/";
...
var element = item.Element(ns + "Document").Element(ns + "Country");
I'd also encourage you to avoid query expressions where they don't actually buy you much. In this case, you could perform the whole query in one go using the Elements extension method which works on sequences of input elements, assuming you don't mind finding every Document -> Country element rather than just one per Data:
var query = root.Descendants(aw + "Data")
.Where(x => (string)x.Attribute(kw + "type") == "green")
.Elements(ns + "Document")
.Elements(ns + "Country")
.Select(x => x.Value);
foreach (var item in query)
{
Console.WriteLine(item);
}
One significant difference - this won't fall over with an exception if there is a Data element with xsi:type='green' which doesn't have a Document -> Country element. If you want it to (to find bad data) you could use:
var query = root.Descendants(aw + "Data")
.Where(x => (string)x.Attribute(kw + "type") == "green")
.Select(x => x.Element(ns + "Document")
.Element(ns + "Country")
.Value);
To show a short but complete example, this code (with your XML as test.xml) gives an output of "1":
using System;
using System.Linq;
using System.Xml.Linq;
public class Program
{
static void Main(string[] args)
{
var doc = XDocument.Load("test.xml");
XNamespace ns = "http://2013-02-01/";
XNamespace kw = "http://www.w3.org/2001/XMLSchema-instance";
XNamespace aw = "http://data.schemas";
var query = doc.Descendants(aw + "Data")
.Where(x => (string)x.Attribute(kw + "type") == "green")
.Elements(ns + "Document")
.Elements(ns + "Country")
.Select(x => x.Value);
foreach (var item in query)
{
Console.WriteLine(item);
}
}
}
I'm working on windows 8 metro apps and i need to get some information from a XML file.
i parse it with LINQ to XML but I've got a problem.
here is the XML:
<feed xmlns="http://www.allocine.net/v6/ns/">
<page>1</page>
<count>1</count>
<results type="movie">10</results>
<results type="person">0</results>
<totalResults>10</totalResults>
<movie code="61282">
<originalTitle>Avatar</originalTitle>
<title>Avatar</title>
<productionYear>2009</productionYear>
<release>
<releaseDate>2010-09-01</releaseDate>
</release>
<castingShort>
<directors>James Cameron</directors>
<actors>Sam Worthington, Zoe Saldana, Sigourney Weaver, Stephen Lang, Michelle Rodriguez</actors>
</castingShort>
<statistics>
<pressRating>4.33333</pressRating>
<userRating>4.31338</userRating>
</statistics>
<poster path="/medias/nmedia/18/78/95/70/19485155.jpg"
href="http://images.allocine.fr/medias/nmedia/18/78/95/70/19485155.jpg"/>
<linkList>
<link rel="aco:web"
href="http://www.allocine.fr/film/fichefilm_gen_cfilm=61282.html"/>
</linkList>
</movie>
</feed>
I need to get "code" value of the "movie" node and the "href" value of the node "link" but all the things i tried failed ...
You can consider that the beginning of the XML is <movie> because I get the file and i parse it to keep the XML clean as I want. my file start with <movie code="">
For a classic value like "actors" i do :
Actors = (string)query.Element("castingShort").Element("actors")
It is working perfectly! My problem is for the specific value with a name.
edit :
that's what i did with your advices.
var group1 = new SampleDataGroup("Group-1", "Films", "", "Assets/icone_groupe_all_movies.jpg", "Films sur le DD");
movieName = "avatar";
Uri = "http://api.allocine.fr/rest/v3/search?partner=YW5kcm9pZC12M3M&filter=movie,person&count=1&page=1&q=" + movieName + "&format=xml";
var httpResponse = await new HttpClient().GetAsync(Uri);
string sourceCode = get_new_xml(await httpResponse.Content.ReadAsStringAsync());
XDocument doc = XDocument.Parse(sourceCode);
XNamespace ns = "http://www.allocine.net/v6/ns/";
XElement movie = doc.Root.Element(ns + "movie");
XElement castingShort = movie.Element(ns + "castingShort");
XElement statistics = movie.Element(ns + "statistics");
Data data = new Data
{
MovieCode = (string)movie.Attribute("code"),
OriginalTitle = (string)movie.Element(ns + "originalTitle"),
Title = (string)movie.Element(ns + "title"),
ProductionYear = (string)movie.Element(ns + "productionYear"),
Directors = (string)castingShort.Element(ns + "directors"),
Actors = (string)castingShort.Element(ns + "actors"),
PressRating = (string)statistics.Element(ns + "pressRating"),
UserRating = (string)statistics.Element(ns + "userRating"),
Cover = (string)movie.Element(ns + "linkList").Element(ns + "link").Attribute("href")
};
group1.Items.Add(new SampleDataItem("Group-1-Item-1", data.Title, data.Cover, data.ProductionYear, "", data.ReleaseDate, group1));
this.AllGroups.Add(group1);
but unfortunately it still doesent work ...
Thus you have namespace declared in your xml, you should declare and initialize an XNamespace object, and to use it when specifying XName objects (arguments to Element methods):
XDocument xdoc = XDocument.Load(path_to_xml);
XNamespace ns = "http://www.allocine.net/v6/ns/";
XElement movie = xdoc.Root.Element(ns + "movie");
var code = (int)movie.Attribute("code");
var href = (string)movie.Element(ns + "linkList")
.Element(ns + "link").Attribute("href");
If you have only one <movie> element, then you don't need to operate on sequence of movie elements and treat single movie as list. Simply get movie node and create new data object via parsing that node:
XNamespace ns = "http://www.allocine.net/v6/ns/";
XElement movie = xdoc.Root.Element(ns + "movie");
XElement castingShort = movie.Element(ns + "castingShort");
XElement statistics = movie.Element(ns + "statistics");
Data data = new Data
{
MovieCode = (int)movie.Attribute("code"),
OriginalTitle = (string)movie.Element(ns + "originalTitle"),
Title = (string)movie.Element(ns + "title"),
ProductionYear = (string)movie.Element(ns + "productionYear"),
Directors = (string)castingShort.Element(ns + "directors"),
Actors = (string)castingShort.Element(ns + "actors"),
PressRating = (string)statistics.Element(ns + "pressRating"),
UserRating = (string)statistics.Element(ns + "userRating"),
Cover = (string)movie.Element(ns + "linkList")
.Element(ns + "link").Attribute("href")
};
I have this LINQ query:
XNamespace ns = NAMESPACE;
var items = (from c in doc.Descendants(ns +"Item")
select new Item
{
Title = c.Element(ns + "ItemAttributes").Element(ns + "Title").Value,
MFR = c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value,
Offer = c.Element(ns + "Offers").Element(ns + "TotalOffers").Value,
Amazon = c.Element(ns + "Offer").Element(ns + "Merchant").Elements(ns + "MerchantId"),
LowPrice = Convert.ToDouble(c.Element(ns + "FormattedPrice").Value),
SalesRank = Convert.ToInt32(c.Element(ns +"SalesRank").Value),
ASIN = c.Element(ns + "ASIN").Value
}).ToList<Item>();
It works great expect for when a node is not present. For example it my not have a MFR or a sales rank. How can I make it so if it does not have the node in question, it gives me a default value or at the very doesn't make me try catch my whole query for one item.
As far as I'm aware LINQ to XML doesn't support this. However I ran into this same mess in a project I was working on and created this extension for XElement to allow it. Maybe it could work for you:
public static XElement ElementOrDummy(this XElement parentElement,
XName name,
bool ignoreCase)
{
XElement existingElement = null;
if (ignoreCase)
{
string sName = name.LocalName.ToLower();
foreach (var child in parentElement.Elements())
{
if (child.Name.LocalName.ToLower() == sName)
{
existingElement = child;
break;
}
}
}
else
existingElement = parentElement.Element(name);
if (existingElement == null)
existingElement = new XElement(name, string.Empty);
return existingElement;
}
Basically it just checks to see if the element exists and if it doesn't it returns one with the same name and an empty value.
You can use XElement Explicit Conversion, e.g.:
(int?)c.Element(ns +"SalesRank")
Reference: http://msdn.microsoft.com/en-us/library/bb340386.aspx
if the problem that the XElement exists, but the value is blank? i.e.
<Item>
<ItemAttributes>
<Manufacturer></Manufacturer>
</ItemAttributes>
</Item>
then you can use the string.IsNullOrEmpty function
XNamespace ns = NAMESPACE;
var items = (from c in doc.Descendants(ns +"Item")
select new Item
{
MFR = if (string.IsNullOrEmpty(c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value)) ? "default value here" : c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value,
// omitted for brevity
}).ToList<Item>();