Given the following XML:
<platforms>
<platform>
<id>1</id>
<price>2.99</price>
</platform>
</platforms>
How can I select the "platform" element as an XElement object based on the child element "id" having a value of "1"?
I have got this far:
XDocument xPlatformXml = new XDocument();
XElement xel = xPlatformXml.Element("platforms").Elements("platform").Where(x => x.Value == "1").SingleOrDefault();
But this is looking for the value to be in "platform" element rather than "id".
XDocument xPlatformXml = new XDocument();
XElement xel = xPlatformXml.Element("platforms")
.Elements("platform")
.Where(x => x.Element("id").Value == "1")
.SingleOrDefault();
Or using XElement to int conversion:
XDocument xPlatformXml = new XDocument();
XElement xel = xPlatformXml.Element("platforms")
.Elements("platform")
.Where(x => (int)x.Element("id") == 1)
.SingleOrDefault();
Related
This is how the XML file could look:
<data>
<subdata>
<datatype id="1" name="data1">
<xdim>2</xdim>
<ydim>1</ydim>
</datatype>
<datatype id="2" name="data2">
<xdim>3</xdim>
<ydim>4</ydim>
</datatype>
</subdata>
</data>
Now, i want the following:
A list(string) with all datatype id's like "1" & "2" in the preview above
A list(string) with all the < xdim > stuff like "2" & "3" above
A list(string) with all the < ydim > stuff like "1" & "4" above
Are there easy methods built in in C# for stuff like this? Or could anyone help me with this question?
Jonas
You can use Descendents method.
This method reads all the child nodes even the nested ones where node name matches with specified string.
var Idstring = MyXml.Descendants("datatype").Select (x=>x.Attribute("Id")).ToList();
var xdimstring = MyXml.Descendants("xdim").Select (x=>x.Value).ToList();
var ydimstring = MyXml.Descendants("ydim").Select (x=>x.Value).ToList();
To Appease your curiosity :)
This how you can get nodes from specifically subdata node.
var Idstring = MyXml.Descendants("Subdata").Descendants("datatype").Select (x=>x.Attribute("Id")).ToList();
var xdimstring = MyXml.Descendants("Subdata").Descendants("xdim").Select (x=>x.Value).ToList();
var ydimstring = MyXml.Descendants("Subdata").Descendants("ydim").Select (x=>x.Value).ToList();
Now let say you have Multiple subdata and you want to read nodes only from first one...Simply use First linq extension method
var Idstring = MyXml.Descendants("Subdata").First().Descendants("datatype").Select (x=>x.Attribute("Id")).ToList();
This works and is fairly neat and simple:
string xml =
#"<data>
<subdata>
<datatype id=""1"" name=""data1"">
<xdim>2</xdim>
<ydim>1</ydim>
</datatype>
<datatype id=""2"" name=""data2"">
<xdim>3</xdim>
<ydim>4</ydim>
</datatype>
</subdata>
</data>";
var xelem = XElement.Parse(xml);
var allIDs = xelem
.Descendants()
.Where (x => x.Attribute("id") != null)
.Select (x => x.Attribute("id").Value)
.ToList();
var allXdims = xelem
.XPathSelectElements("//xdim")
.Select (x => x.Value)
.ToList();
var allYdims = xelem
.XPathSelectElements("//ydim")
.Select (x => x.Value)
.ToList();
Obviously the part at the start is just getting the XML into an XElement. You might want to do this with:
var xelem = XElement.Load(myXmlLocation);
instead.
The easiest way to convert classes to and from XML in C# is XML Serialization
For your example, you could create a class with member variables corresponding to the tags in your XML. When you want to create your XML file, you serialize the class to an XML File.
When your want to read back the information, you deserialize the contents of the XML file back to the class you created.
Here's a more comprehensive article: https://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx
You can use:
XDocument doc = XDocument.Load(#"..\myfile.xml");
to load your file in a XDocument object.
Then use XDocument methods to create string lists of the required id values:
var ids = (from a in doc.Descendants("subdata").Elements().Attributes("id")
select a.Value).ToList();
var xids = (from e in doc.Descendants("datatype").Elements("xdim")
select e.Value).ToList();
var yids = (from e in doc.Descendants("datatype").Elements("ydim")
select e.Value).ToList();
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(
"<data><subdata><datatype id=\"1\" name=\"data1\"><xdim>2</xdim><ydim>1</ydim></datatype><datatype id=\"2\" name=\"data2\"><xdim>3</xdim><ydim>4</ydim></datatype></subdata></data>");
var nodes = xmlDocument.SelectNodes("//datatype");
var first = new List<string>();
var Second = new List<string>();
var third = new List<string>();
foreach (XmlNode node in nodes)
{
first.Add(node.Attributes["id"].Value);
}
nodes = xmlDocument.SelectNodes("//xdim");
foreach (XmlNode node in nodes)
{
Second.Add(node.InnerText);
}
nodes = xmlDocument.SelectNodes("//ydim");
foreach (XmlNode node in nodes)
{
third.Add(node.InnerText);
}
Try something like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication81
{
class Program
{
static void Main(string[] args)
{
string xml =
"<data>" +
"<subdata>" +
"<datatype id=\"1\" name=\"data1\">" +
"<xdim>2</xdim>" +
"<ydim>1</ydim>" +
"</datatype>" +
"<datatype id=\"2\" name=\"data2\">" +
"<xdim>3</xdim>" +
"<ydim>4</ydim>" +
"</datatype>" +
"</subdata>" +
"</data>";
XElement data = XElement.Parse(xml);
var results = data.Descendants("subdata").Elements()
.GroupBy(x => x.Name.LocalName)
.Select(x => new
{
name = x.Key,
value = x.Select(y => (string)y).ToList(),
attributes = x.Attributes()
.Select(y => new {name = y.Name.LocalName, y.Value})
.GroupBy(y => y.name, z => z.Value)
.ToDictionary(y => y.Key, z => z.ToList())
}).ToList();
}
}
}
I want to add an XmlNode to another XmlNode if it doesn't contain this node (the comparison should be based on the node name and its contents)
System.Xml.XmlDocument doc;
...
XmlNode newNode = doc.CreateElement(name);
newNode.InnerXml = something
XmlNode parentNode = doc.GetElementsByTagName(parentName);
if (parentNode.???? (newNode))
{
parentNode.AppendChild(newNode);
}
How can I check this existence? parentNode.ChildNodes doesn't have a Contain method.
I think this will do the trick:
private void doSomething()
{
XmlDocument doc = new XmlDocument();
XmlNode newNode = doc.CreateElement("name");
newNode.InnerXml = "something";
XmlNode parentNode = doc.GetElementsByTagName("parentName")[0];
// I just stuck an index on end of above line...
// Note that GetElementsByTagName returns an XmlNodeList
int huh = 0;
foreach (XmlNode n in parentNode.ChildNodes)
{
// If I understood you correctly, you want these checks?
if (n.InnerXml == newNode.InnerXml && n.Name == newNode.Name) huh++;
}
if (huh == 0) parentNode.AppendChild(newNode);
}
You could do this using LINQ to XML making use of the XNode.DeepEquals method to compare your child nodes for equality. An example might look like this - the duplicateChild will not be added but newChild will be:
var doc = new XDocument(
new XElement("parent",
new XElement("child", 1)));
var parent = doc.Descendants("parent").Single();
var duplicateChild = new XElement("child", 1);
var newChild = new XElement("child", 2);
if (!parent.Elements().Any(e => XNode.DeepEquals(e, duplicateChild)))
{
parent.Add(duplicateChild);
}
if (!parent.Elements().Any(e => XNode.DeepEquals(e, newChild)))
{
parent.Add(newChild);
}
A demo here: https://dotnetfiddle.net/1t4Q1b
How can i find complexType element knowing it's name(station)?
I'm beginner
Here is an entire xsd code:
http://pastebin.com/ymuPDCCb
This doesn't work.
private XElement GetComplexType(string typeName)
{
XElement complexType = xsdSchema.Elements("complexType")
.Where(a => a.Attributes("name").FirstOrDefault() != null && a.Attribute("name").Value==typeName)
.FirstOrDefault();
return complexType;
}
You have to include the xs namespace and you need to query all levels using Descendants() instead of Elements(), like so:
private static void ParseXml()
{
XDocument doc = XDocument.Load(#"C:\schema.xml");
if (doc != null)
{
XElement nodes = GetComplexType("station", doc);
if (nodes != null)
{
Console.WriteLine("station found...");
}
else
{
Console.WriteLine("station NOT found!!");
}
}
}
private static XElement GetComplexType(string typeName, XDocument xsdSchema)
{
XNamespace ns = "http://www.w3.org/2001/XMLSchema";
XElement complexType = xsdSchema.Descendants(ns + "complexType")
.Where(a => a.Attributes("name").FirstOrDefault() != null && a.Attribute("name").Value == typeName)
.FirstOrDefault();
return complexType;
}
Check this SO answer for more info on Elements vs Descendants
This is my current attempt to transform key value pair xml to a C# dictionary:
const string xml = #"<KVP><Id>642</Id><StartDate>2012-03-01T00:00:00</StartDate></KVP>";
var xdoc = XDocument.Parse(xml);
if (xdoc.Root != null)
{
var map = xdoc.Root.Elements()
.ToDictionary(a => a.Name.LocalName,
a => a.Value.Trim());
}
Can this be improved?
I have not used XML for very long and need to extract the useful information from an XML response. If there are 2 tags that are the same but have a different name e.g
<lst name = "stack">
<str>Ola</str>
<lst name = "overflow">
<str>Hello</str>
</lst>
</lst>
How would I extract the contents of the tag with name="overflow"?
You can use LINQ To XML:
var result = XDocument.Parse(xml)
.Descendants("lst")
.Where(e => (string) e.Attribute("name") == "overflow")
.Descendants("str")
.Select(x => x.Value)
.FirstOrDefault();
Try this to start:
XPathDocument docNav = new XPathDocument(pathName);
XPathNavigator nav = docNav.CreateNavigator();
XmlNamespaceManager ns = new XmlNamespaceManager(nav.NameTable);
string val = nav.SelectSingleNode(#"/lst/lst[#name='overflow']/str")
These are good resources for simple XPath navigation and .NET XML Parsing:
http://www.w3schools.com/xpath/
http://www.codeproject.com/Articles/52079/Using-XPathNavigator-in-C
You may use the System.Xml.Linq namespace:
var xDoc = XDocument.Parse(xml);
var result = xDoc.Descendants()
.Where(d =>
d.Name == "lst" &&
d.Attributes("name").FirstOrDefault()!=null &&
d.Attributes("name").FirstOrDefault().Value == "overflow")
.FirstOrDefault();
User Linq to xml
var xmlFile = XDocument.Load(someFile);
var query = from item in xmlFile.Descendants("childobject")
where !String.IsNullOrEmpty(item.Attribute("using")
select new
{
AttributeValue = item.Attribute("using").Value
};
You can do it with LINQ to XML:
var doc = XDocument.Load("YourXMLPath.xml");
var content = doc
.Element("lst")
.Elements("lst")
.Where(e=>((string) e.Attribute("name") ?? "")=="overflow")
.Select(e=>e.Element("str").InnerText())
.FirstOrDefault();
LINQ to XML in System.Xml.Linq namespace.
const string xml = #"<lst name = ""stack""><str>Ola</str><lst name = ""overflow""><str>Hello</str></lst></lst>";
XDocument doc = XDocument.Parse(xml);
IEnumerable<XElement> overflow = doc.Root.Elements("lst").Where(x => (string) x.Attribute("name") == "overflow");
XElement firstOverflow = overflow.FirstOrDefault();
string value = firstOverflow.Descendants("str").FirstOrDefault(x => x.Value);