Okay, so I've been working on reading in a kml file that contains the coordinates of the boundary of every county/city in America. However, I've ran into some problems. Particularly, how to get the value of the NextNode and what to do when there is another element tag in the middle of an element's value.
Here is what the kml file looks like:
<?xml version="1.0" encoding="utf-8" ?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document id="root_doc">
<Schema name="gadm36_USA_2" id="gadm36_USA_2">
<SimpleField name="NAME_0" type="string"></SimpleField>
<SimpleField name="NAME_1" type="string"></SimpleField>
<SimpleField name="NAME_2" type="string"></SimpleField>
</Schema>
<Folder><name>gadm36_USA_2</name>
<Placemark>
<Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style>
<ExtendedData><SchemaData schemaUrl="#gadm36_USA_2">
<SimpleData name="NAME_0">United States</SimpleData>
<SimpleData name="NAME_1">Alabama</SimpleData>
<SimpleData name="NAME_2">Autauga</SimpleData>
</SchemaData></ExtendedData>
<MultiGeometry><Polygon><outerBoundaryIs><LinearRing><coordinates>-86.8189620971679,32.3402709960939 -86.8108367919922,32.3471298217775 -86.8097915649414,32.3535118103028 -86.8103485107422,32.3585205078126 -86.8158340454101,32.3703498840333 -86.8239974975586,32.3785285949708 -86.8310775756835,32.3839797973634 -86.83544921875,32.3912506103515 -86.8419876098633,32.3980712890626 -86.8452758789062,32.4044418334961 -86.8458633422851,32.4140090942383 -86.8447875976562,32.4167404174805 </coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LinearRing><coordinates>-86.8426208496093,32.4181213378907 -86.8361129760742,32.4204101562501 -86.8296127319336,32.4227104187012 -86.8274383544922,32.4240798950195 -86.8263626098633,32.4259109497071 -86.8280029296875,32.4277305603028 -86.8307189941406,32.4295387268066 </coordinates></LinearRing></outerBoundaryIs></Polygon></MultiGeometry>
</Placemark>
Note, this is not an actual example where these random element tags appear in the middle of the coordinates, the counties that have them typically have a massive coordinate list and from my experience if i go through the kml file and only use the values before the first element tags, it appears to map out the correct county boundaries
List<string> locationList = new List<string>();
var doc = XDocument.Load("gadm36_USA1.kml");
XNamespace ns = "http://www.opengis.net/kml/2.2";
var result = doc.Root.Descendants(ns + "Placemark");
foreach (XElement xmlInfo in result)
{
var region = xmlInfo.Element(ns + "ExtendedData").Element(ns + "SchemaData").Value;
//var country = region.Element(ns + "SimpleData").Value;
//var state = region.Element(ns + "SimpleData");
//var cityCounty = region.Element(ns + "SimpleData");
locationList = xmlInfo.Element(ns + "MultiGeometry").Value.Split(' ').ToList();
CountyCoordinates.Add(region, locationList);
}
So when i get to the variable "region", it groups all the element values together. For example it will say "United StatesAutaugaAlabama".
As for the coordinates, since there are these random element tags in the middle of the coordinate values, when i split the coordinates by " ", it gets screwed up when it hits these random element tags. (when it gets to that text in the middle of the coordinates the split will return '-86, 32 -86', instead of just '-86, 32') So, I'm essentially looking for help on how to read in the country, state, and county separately and how to properly read in the coordinates despite these random element tags.
I just tested with following a get results :
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 root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
List<XElement> simpleFields;
List<XElement> extendedDatas = doc.Descendants(ns + "ExtendedData").ToList();
foreach(XElement extendedData in extendedDatas)
{
simpleFields = extendedData.Descendants(ns + "SimpleData").ToList();
}
}
}
}
I think you meant:
List<XElement> extendedDatas = doc.Descendants(ns + "ExtendedData").ToList();
var a_docment = root.Element(ns + "Document").Value;
var result = doc.Root.Descendants(ns + "Placemark");
foreach (XElement xmlInfo in result)
{
List<string> locationList = new List<string>();
var gg = xmlInfo.Descendants(ns + "outerBoundaryIs").ToList();
foreach (XElement extendedData in gg)
{
locationList.AddRange(extendedData.Value.Split(' ').ToList());
}
Related
I have a xml file that looks like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetAllArticlesResponse xmlns="http://www.borger.dk/2009/WSArticleExport/v1">
<GetAllArticlesResult xmlns:a="http://www.borger.dk/2009/WSArticleExport/v1/types" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:ArticleDescription>Test 1</a:ArticleDescription>
<a:ArticleDescription>Test 2</a:ArticleDescription>
</GetAllArticlesResult>
</GetAllArticlesResponse>
</s:Body>
</s:Envelope>
I'm trying to get all the articles, but can't get it to work.
XDocument doc = XDocument.Parse(soapResult);
IEnumerable<XElement> articles = doc.Root.Descendants("a:ArticleDescription");
This has work before, but because the element name as a : then it fails..
Any idea how to fix this.
Thanks for all the inputs.
I ended with::
XNamespace a = "http://www.borger.dk/2009/WSArticleExport/v1/types";
XDocument doc = XDocument.Parse(soapResult);
IEnumerable<XElement> articles = doc.Root.Descendants(a + "ArticleDescription");
List<Article> article = articles.Select(m => new Article()
{
ArticleID = m.Element(a + "ArticleID").Value.ToString(),
ArticleTitle = m.Element(a + "ArticleTitle").Value.ToString(),
ArticleUrl = m.Element(a + "ArticleUrl").Value.ToString(),
LastUpdated = m.Element(a + "LastUpdated").Value.ToString(),
PublishingDate = m.Element(a + "PublishingDate").Value.ToString()
}).ToList();
json = JsonConvert.SerializeObject(article);
Here's an alterante way:
var doc = XDocument.Load(xml);
XNamespace ns1 = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace ns2 = "http://www.borger.dk/2009/WSArticleExport/v1";
XNamespace ns3 = "http://www.borger.dk/2009/WSArticleExport/v1/types";
var result = doc.Element(ns1 + "Envelope")
.Element(ns1 + "Body")
.Element(ns2 + "GetAllArticlesResponse")
.Element(ns2 + "GetAllArticlesResult")
.Elements(ns3 + "ArticleDescription")
.Select(x => x.Value);
Or
var doc = XDocument.Load(xml);
var envelope = doc.Root;
var body = (XElement)envelope.FirstNode;
var getAllArticlesResponse = (XElement)body.FirstNode;
var getAllArticlesResult = (XElement)getAllArticlesResponse.FirstNode;
var articleDescriptions = getAllArticlesResult.Nodes().Cast<XElement>();
var result = articleDescriptions.Select(x => x.Value);
Here is easiest way using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication137
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
string[] description = doc.Descendants().Where(x => x.Name.LocalName == "ArticleDescription").Select(x => (string)x).ToArray();
}
}
}
The prefix a: is a short-for of the namespace name "http://www.borger.dk/2009/WSArticleExport/v1/types", you can see that where the prefix is declared.
You can use namespace-aware XName's when querying:
var descriptions = doc.Root.Descendants(
XName.Get("ArticleDescription", "http://www.borger.dk/2009/WSArticleExport/v1/types"));
Of course you could store the namespaces you want in variables, you don't have to type them out every time.
You can also just look at the local names, if you're not worried about collisions.
var descriptions = doc.Root.Descendants().Where(x => x.Name.LocalName == "ArticleDescription");
I am trying to parse a gml file in C#. That is why I need to select some specific elements on it. What I am trying to do is, selecting coordinates which is located in <lifr:LineString gml:id="ls1">
A part of my gml file looks like:
<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:gml ="http://www.opengis.net/gml/3.2" xmlns:lifr="http://www.opengis.net/infragml/road/1.0" xmlns:xlink="http://www.opengis.net/infragml/road/1.0">
<lifr:stringLineSet>
<lifr:StringLineSet gml:id="sls1">
<gml:description>string lines delineating the top pavement surface</gml:description>
<gml:name>top surface pavement</gml:name>
<lifr:stringLineSetID>
<lifr:ID>
<identifier>pavement1</identifier>
</lifr:ID>
</lifr:stringLineSetID>
<lifr:stringLine>
<lifr:StringLine gml:id="sl1">
<gml:description>top surface</gml:description>
<gml:name>left edge pavement</gml:name>
<lifr:stringLineID>
<lifr:ID>
<identifier>LEP</identifier>
</lifr:ID>
</lifr:stringLineID>
<lifr:geometry>
<lifr:LineString gml:id="ls1">
<gml:pos>-3.650 1000 49.927</gml:pos>
<gml:pos>-3.650 1100 48.927</gml:pos>
</lifr:LineString>
</lifr:geometry>
</lifr:StringLine>
</lifr:stringLine>
<lifr:stringLine>
<lifr:StringLine gml:id="sl2">
<gml:description>top surface</gml:description>
<gml:name>centerline pavement</gml:name>
<lifr:stringLineID>
<lifr:ID>
<identifier>CLP</identifier>
</lifr:ID>
</lifr:stringLineID>
<lifr:geometry>
<lifr:LineString gml:id="ls2">
<gml:pos>0.000 1000 50.000</gml:pos>
<gml:pos>0.000 1100 49.000</gml:pos>
</lifr:LineString>
</lifr:geometry>
<lifr:alternativeGeometry xlink:href="ac1"/>
</lifr:StringLine>
</lifr:stringLine>
<lifr:stringLine>
<lifr:StringLine gml:id="sl3">
<gml:description>top surface</gml:description>
<gml:name>right edge pavement</gml:name>
<lifr:stringLineID>
<lifr:ID>
<identifier>REP</identifier>
</lifr:ID>
</lifr:stringLineID>
<lifr:geometry>
<lifr:LineString gml:id="ls3">
<gml:pos>3.650 1000 49.927</gml:pos>
<gml:pos>3.650 1100 48.927</gml:pos>
</lifr:LineString>
</lifr:geometry>
</lifr:StringLine>
</lifr:stringLine>
</lifr:StringLineSet>
</lifr:stringLineSet>
</root>
I tried to write coordinates to console with the code below but I just got blank console.
XNamespace gml = "http://www.opengis.net/gml/3.2";
XNamespace lifr = "http://www.opengis.net/infragml/road/1.0";
XDocument xmlDoc = XDocument.Load(#"C:\Road_example.gml");
IEnumerable<XElement> pavement =
from el in xmlDoc.Elements().Elements(lifr + "LineString")
where (string)el.Attribute(gml + "id") == "ls1"
select xmlDoc.Parent.Element(gml + "pos");
foreach (XElement coords in pavement)
Console.WriteLine(coords);
Console.ReadKey();
Here is solution :
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication75
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XNamespace gml = "http://www.opengis.net/gml/3.2";
XNamespace lifr = "http://www.opengis.net/infragml/road/1.0";
XDocument xmlDoc = XDocument.Load(FILENAME);
List<XElement> pavement = xmlDoc.Descendants(lifr + "LineString").ToList();
foreach (XElement coords in pavement)
{
string id = (string)coords.Attribute(gml + "id");
string pos = string.Join(",", coords.Elements(gml + "pos").Select(x => (string)x));
Console.WriteLine("id = '{0}', positions = '{1}'", id, pos);
}
//with filtered results
var ls1 = pavement.Where(x => (string)x.Attribute(gml + "id") == "ls1").FirstOrDefault();
string positions = string.Join(",", ls1.Elements(gml + "pos").Select(x => (string)x));
Console.ReadKey();
}
}
}
I have the following XML:
<resource>
<description>TTT</description>
<title>TEST</title>
<entity xmlns="TdmBLRuPlUz.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="TdmBLRuPlUz.xsd TdmBLRuPlUz.xsd">
<UzdProd>
<row>
<F_DAUDZ>50</F_DAUDZ>
<BR_DAUDZ/>
<DAUDZ>50</DAUDZ>
<U_DAUDZ/>
<NKODS>ST2.0_014_023</NKODS>
</row>
</UzdProd>
<UzdMat>
<row>
<NKODS>SAG 2.0_014_150</NKODS>
<NNOSAUK>Sagatave 2.0mm*0.14*150m</NNOSAUK>
<PK_VIEN>1</PK_VIEN>
<DAUDZ>0.077</DAUDZ>
<F_DAUDZ>0.077</F_DAUDZ>
</row>
</UzdMat>
</entity>
</resource>
And this is my C# code:
XNamespace ns = "TdmBLRuPlUz.xsd";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants(ns + "row"))
{
Console.WriteLine(element.Element(ns + "NKODS").Value);
string NKODS = element.Element(ns + "NKODS").Value;
string F_DAUDZ = element.Element(ns + "F_DAUDZ").Value;
string DAUDZ = element.Element(ns + "DAUDZ").Value;
}
What I need is to read values from the XML nodes NKODS, F_DAUDZ and DAUDZ.
The problem is that there are repeating nodes with those names and with this code it gives me the last ones which are under UzdMat node. What would be the way to get the values for these nodes under UzdProd?
I tried to change row to UzdProd, but that didn't work.
You need to read the specific row you want rather than looping through all of them. For example:
var prodRow = doc.Descendants(ns + "UzdProd").Elements(ns + "row").Single();
var matRow = doc.Descendants(ns + "UzdMat").Elements(ns + "row").Single();
var prodNkods = (string) prodRow.Element(ns + "NKODS");
var matNkods = (string) matRow.Element(ns + "NKODS");
See this fiddle for a working demo.
See if this works :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication25
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement entity = doc.Descendants().Where(x => x.Name.LocalName == "entity").FirstOrDefault();
XNamespace ns = entity.GetDefaultNamespace();
var results = entity.Elements().Select(x => new {
uzd = x.Name.LocalName,
dict = x.Descendants(ns + "row").Elements().GroupBy(y => y.Name.LocalName, z => (string)z)
.ToDictionary(y => y.Key, z => z.FirstOrDefault())
}).ToList();
}
}
}
I'm almost getting there, but I need some help.
This is the code that I use to process our XML file. I'm able to find the section that I need to store; I just don't know how to save it.
XmlDocument doc = new XmlDocument();
doc.XmlResolver = null;
doc.Load(#"c:\xml\Sales.xml");
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("nd/ni/nv/noid");
foreach (XmlNode node in nodes)
{
if (node.OuterXml.IndexOf("Server=1,Function=1,Location=") > 0)
{
Console.WriteLine(node.OuterXml);
// This prints out "<noid>Server=1,Function=1,Location=24</noid>"
// How do I read the four <r> nodes within this <noid>?
// The values would be [124, 2, 43, 90]
}
}
The xml looks something like this:
<nd>
<ni>
<nv>
<noid>Managed=1,Network=1,smtp=1</noid>
<r>27</r>
<r>4</r>
</nv>
<nv>
<noid>Managed=1,Network=1,Ibc=1</noid>
<r>8</r>
<r>2</r>
</nv>
<nv>
<noid>Server=1,Function=1,Location=24</noid>
<r>124</r>
<r>2</r>
<r>43</r>
<r>90</r>
</nv>
<nv>
<noid>Unmanaged=9,Label=7,Place=5</noid>
<r>10</r>
<r>20</r>
</nv>
</ni>
</nd>
Console.WriteLine prints the correct <noid> text, so I know that I've already found the section with the relevant data.
My question is, how can I read the four <r> inside this <noid>? Ideally, within the IF statement, how can I read all the <r> elements that are between the <nv></nv>?
Thanks.
Using Linq-to-xml
var xmlText = File.ReadAllText(#"C:\YourDirectory\YourFile.xml");
var xDoc = XDocument.Parse(xmlText);
var rValues = new List<string>(); //THIS IS YOUR RESULT
var nvNodes = xDoc.Descendants("nv");
foreach(var el in nvNodes)
{
if (el.Element("noid").Value.Contains("Server=1,Function=1,Location="))
rValues = el.Elements("r").Select(e => e.Value).ToList();
}
Or, replacing the foreach with Linq (fails if First() is not satisfied)
var rValues = nvNodes.
First(nv => nv.Value.Contains("Server=1,Function=1,Location="))
.Elements("r")
.Select(r => r.Value);
A non-optimized, non-linq solution
XmlDocument doc = new XmlDocument();
doc.XmlResolver = null;
doc.Load(#"C:\YourDirectory\YourFile.xml");
var rValues = new List<string>(); //THIS IS YOUR RESULT
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("//nd/ni/nv");
foreach (XmlNode node in nodes)
{
if (node.FirstChild.InnerText.Contains("Server=1,Function=1,Location="))
{
foreach(XmlNode childnode in node.ChildNodes)
{
if (childnode.Name == "r")
rValues.Add(childnode.InnerText);
}
}
}
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input =
"<nd>" +
"<ni>" +
"<nv>" +
"<noid>Managed=1,Network=1,smtp=1</noid>" +
"<r>27</r>" +
"<r>4</r>" +
"</nv>" +
"<nv>" +
"<noid>Managed=1,Network=1,Ibc=1</noid>" +
"<r>8</r>" +
"<r>2</r>" +
"</nv>" +
"<nv>" +
"<noid>Server=1,Function=1,Location=24</noid>" +
"<r>124</r>" +
"<r>2</r>" +
"<r>43</r>" +
"<r>90</r>" +
"</nv>" +
"<nv>" +
"<noid>Unmanaged=9,Label=7,Place=5</noid>" +
"<r>10</r>" +
"<r>20</r>" +
"</nv>" +
"</ni>" +
"</nd>";
XElement nd = XElement.Parse(input);
var results = nd.Descendants("nv").Select(x => new
{
noid = (string)x.Element("noid"),
r = x.Elements("r").Select(y => (int)y).ToList()
}).ToList();
}
}
}
A short, but difficult to understand XPath expression:
XmlNodeList rNodes = root.SelectNodes(
"nd/ni/nv[noid/text()[contains(.,'Server=1,Function=1,Location=')]]/r");
foreach (XmlNode rNode in rNodes)
Console.WriteLine(rNode.InnerText);
I'm trying to change the value of Xml elements :
<string id="68056"><![CDATA[Anti-Aliasing:]]></string>
<string id="68085"><![CDATA[V Sync:]]></string>
<string id="68100"><![CDATA[Frame Limit:]]></string>
<string id="68125"><![CDATA[Pixel Light Count:]]></string>
<string id="68162"><![CDATA[Shadow Cascades:]]></string>
<string id="68195"><![CDATA[* Game requires restart for changes to take effect *]]></string>
<string id="68300"><![CDATA[Video & Graphics]]></string>
<string id="68333"><![CDATA[Anti-Aliasing: ]]></string>
<string id="68368"><![CDATA[Texture Quality: ]]></string>
<string id="68403"><![CDATA[Pixel Light Count: ]]></string>
<string id="68442"><![CDATA[Shadow Cascades: ]]></string>
<string id="68477"><![CDATA[Graphics]]></string>
<string id="68494"><![CDATA[AddonLoader: Exception iterating ']]></string>
I've got thousands of lines like those.
I want to change the values in the < !CDATA[ ... ]> section, relatively to the id value. This is the void I made, but it doesn't work.
public static void SetElement(int id, string text)
{
XmlDocument doc = new XmlDocument();
doc.Load(File.OpenRead(PATH));
foreach (XmlNode item in doc.DocumentElement.ChildNodes)
{
if (int.Parse(((XmlElement)item).GetAttribute("id")) == id)
{
doc.CreateCDataSection(text);
doc.Save(PATH);
}
}
}
I've also tried using doc.DocumentElement.Value = text instead of doc.CreateCDataSection(text), it didn't work either.
Can you give me a working void, please ? :)
First, I would suggest using LINQ to XML rather than the older XmlDocument model - it's a lot easier to work with.
public static void SetElement(int id, string text)
{
var doc = XDocument.Load(PATH);
var element = doc.Descendants()
.Single(e => (int)e.Attribute("id") == id);
element.ReplaceNodes(new XCData(text));
doc.Save(PATH);
}
Though this code will work it's not ideal - you are parsing, searching and writing the whole document every time. If you are going to change the contents of more than one element you should re-use the XDocument and only save once finished.
One possible way using XmlDocument :
public static void SetElement(int id, string text)
{
XmlDocument doc = new XmlDocument();
doc.Load(File.OpenRead(PATH));
var xpath = String.Format("//*[#id='{0}']", id);
var str = doc.SelectSingleNode(xpath);
var cdata = (XmlCDataSection)str.FirstChild;
cdata.InnerText = text;
doc.Save(PATH);
}
Or if you can afford to switch to newer API, XDocument :
public static void SetElement(int id, string text)
{
var doc = XDocument.Load(PATH);
var str = docx.Descendants()
.FirstOrDefault(o => (int?)o.Attribute("id") == id);
var cdata = (XCData)str.FirstNode;
cdata.Value = text;
doc.Save(PATH);
}
Try something like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string parent =
"<parent>" +
"<string id=\"68056\"><![CDATA[Anti-Aliasing:]]></string>" +
"<string id=\"68085\"><![CDATA[V Sync:]]></string>" +
"<string id=\"68100\"><![CDATA[Frame Limit:]]></string>" +
"<string id=\"68125\"><![CDATA[Pixel Light Count:]]></string>" +
"<string id=\"68162\"><![CDATA[Shadow Cascades:]]></string>" +
"<string id=\"68195\"><![CDATA[* Game requires restart for changes to take effect *]]></string>" +
"<string id=\"68300\"><![CDATA[Video & Graphics]]></string>" +
"<string id=\"68333\"><![CDATA[Anti-Aliasing: ]]></string>" +
"<string id=\"68368\"><![CDATA[Texture Quality: ]]></string>" +
"<string id=\"68403\"><![CDATA[Pixel Light Count: ]]></string>" +
"<string id=\"68442\"><![CDATA[Shadow Cascades: ]]></string>" +
"<string id=\"68477\"><![CDATA[Graphics]]></string>" +
"<string id=\"68494\"><![CDATA[AddonLoader: Exception iterating ']]></string>" +
"</parent>";
StringReader reader = new StringReader(parent);
XDocument doc = XDocument.Load(reader);
var results = doc.Root.Elements("string").OrderBy(x => x.Attribute("id").Value);
}
}
}