Looping through Descendants of an XDocument - C# - c#

Does anybody know why the following code doesn't find any Descendants named "PntList3D" in the XDocument? I've run similar code with xml files from different sources and it's worked just fine.
XDocument xdoc = XDocument.Load(file);
foreach (XElement pntList3D in xdoc.Descendants("PntList3D"))
{
//No XElements found?
string[] coords = pntList3D.Value.Split(separator);
//........
}
The XML file is as follows:
<?xml version="1.0" encoding="iso-8859-1" ?>
<LandXML xmlns="http://www.landxml.org/schema/LandXML-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.landxml.org/schema/LandXML-1.0 http://www.landxml.org/schema/landxml-1.0/LandXML-1.0.xsd" version="1.0" date="2018-05-21" time="10:54:45">
<Units>
<Metric areaUnit="squareMeter" linearUnit="meter" volumeUnit="cubicMeter" temperatureUnit="celsius" pressureUnit="HPA" angularUnit="radians" directionUnit="radians"/>
</Units>
<Application name="Bentley Rail Track V8i (SELECTseries 4)" manufacturer="Bentley Systems, Inc." version="08.11.09.878" manufacturerURL="www.bentley.com"/>
<Surfaces>
<Surface name="GUCanalFinalGround" state="proposed">
<SourceData>
<Breaklines>
<Breakline brkType="standard" name="Merge Boundary Breakline13">
<PntList3D>
373369.843784061 201940.481405058 100.010000000 373346.803045009 201978.937591557 100.266579521 373345.131682429 201986.094864832 100.285820869 373344.675829289 201994.051291911 100.305094741 373343.948058537 202002.377250983 100.325783280 373347.097559184 202015.927410062 100.351677422 373349.064121068 202028.461854698 100.377340245 373349.158000706 202037.105375695 100.397451931 373349.558848160 202047.019625644 100.420035342 373351.626002592 202059.961277642 100.444814507 373351.012091134 202068.660831945 100.465852191 373341.758274428 202103.172391947 100.582514748 373319.443256788 202115.548623449 100.621330067 373314.187088077 202116.429655954 100.632560880 373309.015283797 202117.464532283 100.644344390 373296.621004758 202116.103443765 100.663523942 373291.562007714 202117.732947895 100.675479985 373281.143675082 202119.484060498 100.698356878 373276.337524008 202120.933216769 100.710662078 373272.233432380 202123.836471532 100.724192638 373261.827555133 202125.960550682 100.747355849 373251.520869727 202128.251385445 100.770700659 373245.559103071 202128.214153277 100.781125221 373239.789665844 202128.349784236 100.791427303 373229.601950129 202130.619067512 100.814814992 373225.304350337 202132.986580328 100.828137161 373214.890815224 202136.688095193 100.839157834 373210.210442728 202138.686367756 100.852302328 373204.606106857 202142.207609670 100.866054658 373191.545497214 202148.081237003 100.918005418 373176.562316984 202152.361356766 100.954250454 373171.044645747 202154.053893695 100.966278732 373166.208397576 202155.713237010 100.978687738 373160.708995109 202155.679722689 100.989287494 373155.688534545 202156.493295914 101.000834112 373150.482235484 202157.176413548 101.012161143 373144.212549179 202156.159209438 101.021467326 373137.448440098 202156.600718164 101.031754759 373131.391817655 202156.182136957 101.041765542 373125.390422036 202155.709761447 101.051750480 373119.276552408 202155.069671573 101.061523722 373054.430807066 202143.721890221 102.441500000 373058.442814638 202140.697787490 102.328000000 373066.166069761 202134.158949750 101.933000000 373073.565553867 202127.092819841 101.360000000 373080.608667856 202119.447463058 100.589000000 373087.692942040 202111.870287954 99.839000000 373091.238928264 202108.087310204 99.465000000 373092.286790268 202109.791671688 99.504983646 373095.832728759 202106.008743033 99.130988179 373102.878820288 202098.368395826 98.353988013 373110.583835192 202091.800057704 97.934987722 373118.123075009 202084.962016843 97.421992176 373125.392085793 202077.684336252 96.759009538 373132.990746979 202070.942967185 96.274010799 373140.640127087 202064.284112116 95.814017469 373150.541354297 202061.288814036 96.578880626 373155.592889845 202050.403490658 94.696924444 373161.444949212 202040.820548117 93.249013491 373170.040905925 202035.701685379 93.293999781 373178.501762418 202030.363025321 93.264000224 373187.026261039 202025.127904379 93.265000042 373195.553374235 202019.897036065 93.265999882 373204.080773941 202014.666632815 93.264000015 373212.683146019 202009.558202046 93.299998484 373221.146334288 202004.223330229 93.258000145 373229.732436104 201999.088427042 93.279999413 373238.278154811 201993.887822981 93.277999879 373246.827935106 201988.693825711 93.275000301 373255.419702686 201983.568137077 93.292999519 373270.410218672 201988.852661245 96.796999371 373278.832148334 201983.450659530 96.717001898 373287.478398532 201978.413607052 96.756999575 373296.854035216 201974.563203038 97.191991671 373306.521867266 201971.188175126 97.782985073 373316.068961675 201967.616716606 98.305980919 373325.538253354 201963.918678862 98.785012746 373334.774518673 201959.841526182 99.132990669 373333.727060669 201958.136888591 99.093000000 373342.581640977 201953.439507703 99.231000000 373351.873048413 201949.452662854 99.604000000 373360.885734860 201945.010817605 99.823000000 373369.843784061 201940.481405058 100.010000000
</PntList3D>
<Feature code="Breakline">
<Property label="guid" value="210f4f9d-6f98-4246-8967-4b11eb616339"/>
<Property label="style" value="Default"/>
<Property label="triangulate" value="true"/>
<Property label="pointDensity" value="0.000000000"/>
</Feature>
</Breakline>
<Breakline brkType="standard" name="DB75">
<PntList3D>
373095.450629438 202114.938959557 101.014871165 373092.286790268 202109.791671688 99.504983646
</PntList3D>
<Feature code="Breakline">
<Property label="guid" value="9d937eeb-bcf1-4d51-97c1-080736d60adb"/>
<Property label="style" value="Default"/>
<Property label="triangulate" value="true"/>
<Property label="pointDensity" value="0.000000000"/>
</Feature>
</Breakline>
<Breakline brkType="standard" name="DB74">
<PntList3D>
373054.430807066 202143.721890221 102.441500000 373095.450629438 202114.938959557 101.014871165
</PntList3D>
<Feature code="Breakline">
<Property label="guid" value="71b6272a-99f3-483c-b997-4b3b82de6984"/>
<Property label="style" value="Default"/>
<Property label="triangulate" value="true"/>
<Property label="pointDensity" value="0.000000000"/>
</Feature>
</Breakline>
</Breaklines>
</SourceData>
</Surface>
</Surfaces>
</LandXML>
I couldn't submit this question as apparently I had too much code and not enough detail. I'm pretty sure the amount of detail I provided was adequate so the following text is just to get this question through the Stackoverflow Bots.

Please try the following approach.
The entire XML is bound to a default namespace.
First, you need to get a default namespace just once.
Second, use it any time while referring to the XML element names.
c#
void Main()
{
const string FILENAME = #"e:\Temp\LandXML.xml";
XDocument xdoc = XDocument.Load(FILENAME);
XNamespace ns = xdoc.Root.GetDefaultNamespace();
foreach (XElement pntList3D in xdoc.Descendants(ns + "PntList3D"))
{
Console.WriteLine(pntList3D.Value + Environment.NewLine);
}
}

You need to specify the namespace in your call for Descendants:
foreach (var pntList3D in xdoc.Descendants(XName.Get("PntList3D","http://www.landxml.org/schema/LandXML-1.0")))
{
//No XElements found?
string[] coords = pntList3D.Value.Split(separator);
//........
}

Related

How to get the value of a child element in xml

I am trying to edit a existing XML file through C# and need to identify the sections I want (block name="treeDeadTree01" and block name="treeDeadTree02") Then get the value of "count" in the child element "drop". I have been able to identify the elements (block name="treeDeadTree01" and block name="treeDeadTree02") but cant figure out how to get the value of "count" from the element "drop" of the specific elements (block name="treeDeadTree01" and block name="treeDeadTree02")
The XML file is a config file from the game 7 Days To Die and I am trying to make a application to more easily edit the configs of the game. After I find the value of "count" I am putting it into a DataGridView.
My question is, how after I find the block element I want do I find the value of "count" in the "drop" child element of the block element?
This is a section of the XML file I am trying to edit
<blocks>
<block name="treeDeadTree01">
<property name="Extends" value="treeMaster" />
<property name="Model" value="Entities/Trees/White_Oak22Prefab" />
<property name="ModelOffset" value="0,-0.3,0" />
<property name="MultiBlockDim" value="1,4,1" />
<property name="BigDecorationRadius" value="4" />
<property name="Collide" value="movement,melee,bullet,arrow,rocket" />
<drop event="Harvest" name="resourceWood" count="515" tag="oreWoodHarvest" />
<property name="ParticleOnDeath" value="treeGib_dead_01" />
<!-- <drop event="Destroy" name="treePlantedMaple1m" count="x"/> -->
<property name="SortOrder2" value="0140" />
<!-- SortTree -->
</block>
<block name="treeDeadTree02">
<!-- almost a shrub -->
<property name="Extends" value="treeMaster" />
<property name="IsTerrainDecoration" value="true" />
<property name="Model" value="Entities/Trees/Haunted_Shrub_WastelandPrefab" />
<property name="ModelOffset" value="0,-0.3,0" />
<property name="Collide" value="melee,rocket" />
<!-- no movement effect on Shape="ModelTree" -->
<drop event="Harvest" name="resourceWood" count="215" tag="oreWoodHarvest" />
<property name="ParticleOnDeath" value="treeGib_dead_02" />
<!-- <drop event="Destroy" name="treePlantedMaple1m" count="x"/> -->
<property name="FilterTags" value="foutdoor,ftrees,fshrubbery" />
<property name="SortOrder1" value="a060" />
</block>
</blocks
My current code
string[] GatherRateNames = {"treeDeadTree01", "treeDeadTree02"};
string XMLBlocksPath = "F:\\SteamLibrary\\steamapps\\common\\7 Days To Die\\Data\\Config\\blocks.xml";
private void makeGatherRatesList()
{
XmlDocument doc = new XmlDocument();
doc.Load(XMLBlocksPath);
XmlNodeList aNodes = doc.SelectNodes("/blocks/block");
foreach (XmlNode aNode in aNodes)
{
XmlAttribute idAttribute = aNode.Attributes["name"];
if (GatherRateNames.Contains(idAttribute.ToString()))
{
addItemToList(idAttribute.ToString(),"Value of count");
}
}
}
private void addItemToList(string itemName, int itemValue)
{
}
In the end I want to get the name of the block like "treeDeadTree01" then get the value of "count" inside the element "drop" of that block and put both of those in a DataGridView and be able to edit the value of count through the DataGridView then repeat that with every block I need.
Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
CultureInfo culture = (CultureInfo)CultureInfo.InvariantCulture.Clone();
culture.NumberFormat.NumberDecimalSeparator = ",";
culture.NumberFormat.NumberGroupSeparator = ".";
XmlReader reader = XmlReader.Create(FILENAME);
List<Block> blocks = new List<Block>();
while (!reader.EOF)
{
if (reader.Name != "block")
{
reader.ReadToFollowing("block");
}
if (!reader.EOF)
{
Block newBlock = new Block();
blocks.Add(newBlock);
XElement xBlock = (XElement)XElement.ReadFrom(reader);
newBlock.name = (string)xBlock.Attribute("name");
XElement drop = xBlock.Element("drop");
if (drop != null)
{
object count = drop.Attribute("count");
newBlock.count = (count == null)? null : (decimal?)decimal.Parse((string)count, culture);
}
}
}
}
public class Block
{
public string name { get; set; }
public decimal? count { get; set; }
}
}
}

How to read xml element from the following file?

I have the following xml file and I am trying to read name element which I am not able to, any idea how can I read that and other elements ?
<?xml version="1.0" encoding="us-ascii"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
<name>tata</name>
<SSIDConfig>
<SSID>
<name>SampleSingleSignOn</name>
</SSID>
</SSIDConfig>
<connectionType>ESS</connectionType>
<connectionMode>auto</connectionMode>
<autoSwitch>false</autoSwitch>
<MSM>
<security>
<authEncryption>
<authentication>WPA2</authentication>
<encryption>AES</encryption>
<useOneX>true</useOneX>
</authEncryption>
<OneX xmlns="http://www.microsoft.com/networking/OneX/v1">
<cacheUserData>true</cacheUserData>
<maxAuthFailures>3</maxAuthFailures>
<authMode>user</authMode>
<singleSignOn>
<type>preLogon</type>
<maxDelay>10</maxDelay>
</singleSignOn>
<EAPConfig>
<EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig"
xmlns:eapCommon="http://www.microsoft.com/provisioning/EapCommon"
xmlns:baseEap="http://www.microsoft.com/provisioning/BaseEapMethodConfig">
<EapMethod>
<eapCommon:Type>25</eapCommon:Type>
<eapCommon:AuthorId>0</eapCommon:AuthorId>
</EapMethod>
<Config xmlns:baseEap="http://www.microsoft.com/provisioning/BaseEapConnectionPropertiesV1"
xmlns:msPeap="http://www.microsoft.com/provisioning/MsPeapConnectionPropertiesV1"
xmlns:msChapV2="http://www.microsoft.com/provisioning/MsChapV2ConnectionPropertiesV1">
<baseEap:Eap>
<baseEap:Type>25</baseEap:Type>
<msPeap:EapType>
<msPeap:ServerValidation>
<msPeap:DisableUserPromptForServerValidation>false</msPeap:DisableUserPromptForServerValidation>
<msPeap:TrustedRootCA />
</msPeap:ServerValidation>
<msPeap:FastReconnect>true</msPeap:FastReconnect>
<msPeap:InnerEapOptional>0</msPeap:InnerEapOptional>
<baseEap:Eap>
<baseEap:Type>26</baseEap:Type>
<msChapV2:EapType>
<msChapV2:UseWinLogonCredentials>true</msChapV2:UseWinLogonCredentials>
</msChapV2:EapType>
</baseEap:Eap>
<msPeap:EnableQuarantineChecks>false</msPeap:EnableQuarantineChecks>
<msPeap:RequireCryptoBinding>false</msPeap:RequireCryptoBinding>
<msPeap:PeapExtensions />
</msPeap:EapType>
</baseEap:Eap>
</Config>
</EapHostConfig>
</EAPConfig>
</OneX>
</security>
</MSM>
</WLANProfile>
And I am reading like this:
XDocument xdoc = XDocument.Load("xmlfile1.xml");
xdoc.Root.Element("name")
it returns null element.
You have to take the XML namespace into account:
XNamespace ns = "http://www.microsoft.com/networking/WLAN/profile/v1";
XElement name = xdoc.Root.Element(ns + "name");

How to extract all nodes of same level

I am trying to get all folder caption attribute and want to store in list
Below is my XML File
<?xml version="1.0" encoding="utf-16" ?>
<Folders Name="MyFolderName">
<Folder Caption="Bank">
<Card Caption="BankName1">
<Property Type="String" Caption="Bank">Bank1</Property>
</Card>
<Card Caption="BankName2">
<Property Type="String" Caption="Bank">Bank2</Property>
</Card>
</Folder>
<Folder Caption="Bills">
<Card Caption="BillName1">
<Property Type="Numeric" Caption="BillName">BillName1Data</Property>
</Card>
<Card Caption="BillName2">
<Property Type="Numeric" Caption="BillName1">BillName2Data</Property>
</Card>
</Folder>
</Folders>
below is my query
public static List<Folder> ExtractFolders()
{
XDocument doc = XDocument.Load(#"I:\WindowsPhone\xmlTesting\xmlTesting\Data\VaultData.xml");
List<Folder> folders = (from c in doc.Descendants("Folders")
select new Folder()
{
Caption = c.Element("Folder").Attribute("Caption").Value
}).ToList<Folder>();
return folders;
}
I am getting only first folder
How can I can I get list of folders
Change
List<Folder> folders = (from c in doc.Descendants("Folders")
select new Folder()
{
Caption = c.Element("Folder").Attribute("Caption").Value
}).ToList<Folder>();
to
List<Folder> folders = (from c in doc.Descendants("Folder")
select new Folder()
{
Caption = c.Attribute("Caption").Value
}).ToList<Folder>();

Changing values in XML file

I need to change password values in my configuration.xml .
Password need to be changed for following users :
tsuer1
github
wtsntro
wtsntrw and so on.
Format of configuration.xml file is like following :
<?xml version="1.0" encoding="UTF-8"?>
<server xmlns="urn:jboss:domain:1.2">
<extensions>
<extension module="org.jboss.as.clustering.infinispan" />
<extension module="org.jboss.as.cmp" />
<extension module="org.jboss.as.ejb3" />
</extensions>
<system-properties>
<property name="SERVER" value="JBOSS" />
<property name="FTP_USER" value="adobenet\wtsntrw" />
<property name="FTP_PASSWORD" value="password value" />
<property name="FTP_READ_USER" value="adobenet\\wtsntro" />
<property name="FTP_READ_PASS" value="password value" />
<property name="API_SECRET_KEY" value="wxrocks" />
<property name="API_ENV" value="regular" />
<property name="PRERELEASE_PASSWORD" value="prerelease" />
<property name="watson.git_user" value="github" />
<property name="watson.git_pwd" value="password value" />
<property name="teststudio.user" value="tsuser1" />
<property name="teststudio.pwd" value="password value" />
</system-properties>
</server>
And following is the code i tried but failed :
XmlDocument doc = new XmlDocument();
string path = #"C:\Users\karansha\Desktop\configuration.xml"; // location of configuration.xml file.
doc.Load(path);
// Using foreach loop for specific Xmlnodes.
foreach (XmlNode selectNode in doc.SelectNodes("server/system-properties/property"))
{
if (selectNode.Attributes["name"].Value == "teststudio.pwd") // tsuser1
{
selectNode.Attributes["value"].Value = "new password"; // changes password value for "FTP_USER".
}
if (selectNode.Attributes["name"].Value == "watson.git_pwd") //github
{
selectNode.Attributes["value"].Value = "new passwordx"; // changes password value for "FTP_READ_USER".
}
if (selectNode.Attributes["name"].Value == "FTP_READ_PASS") // wtsntro
{
selectNode.Attributes["value"].Value = "new_passwordy"; // changes password value for "FTP_PASSWORD".
}
}
doc.Save(path); // Save changes.
Console.WriteLine("Password changed successfully");
Console.ReadLine();
Your Xml elements are contained in a NameSpace, so your XPath needs to account for that.
See:
XPath on an XML document with namespace
XML Namespaces and How They Affect XPath and XSLT
XmlDocument doc = new XmlDocument();
doc.Load(path);
var nm = new XmlNamespaceManager(doc.NameTable);
nm.AddNamespace("jb", "urn:jboss:domain:1.2");
foreach (XmlNode selectNode in doc.SelectNodes("jb:server/jb:system-properties/jb:property", nm))
{
if (selectNode.Attributes["name"].Value == "teststudio.pwd") // tsuser1
{
selectNode.Attributes["value"].Value = "new password"; // changes password value for "FTP_USER".
}
if (selectNode.Attributes["name"].Value == "watson.git_pwd") //github
{
selectNode.Attributes["value"].Value = "new passwordx"; // changes password value for "FTP_READ_USER".
}
if (selectNode.Attributes["name"].Value == "FTP_READ_PASS") // wtsntro
{
selectNode.Attributes["value"].Value = "new_passwordy"; // changes password value for "FTP_PASSWORD".
}
}
doc.Save(path); // Save changes.
Console.WriteLine("Password changed successfully");
You have to specify the namespace:
var nm = new XmlNamespaceManager(doc.NameTable);
if (doc.ChildNodes.Count != 2)
throw new XmlException("Document is not well formated.");
var serverNode = doc.ChildNodes[1];
nm.AddNamespace("a", serverNode.NamespaceURI);
foreach (XmlNode selectNode in
doc.SelectNodes("a:server/a:system-properties/a:property", nm))
{
// ...
}

How can I iterate on XML elements from an XML using XMLReader and bypass whitespaces?

Let say you have an XML like this:
<?xml version="1.0" encoding="utf-8"?>
<Class HashCode="307960707">
<Person>
<Class HashCode="-2020100801">
<FullName>
<FirstName>Dan</FirstName>
<LastName>K</LastName>
</FullName>
</Class>
<Age>20</Age>
<Class HashCode="-439631396">
<Address>
<Street>abc</Street>
<City>new york</City>
<ZipCode>30500</ZipCode>
<PhoneNumber>1245</PhoneNumber>
</Address>
</Class>
<Class HashCode="-1436395737">
<Person>
<Class HashCode="-1303968324">
<FullName>
<FirstName>katty</FirstName>
<LastName>G</LastName>
</FullName>
</Class>
<Age>18</Age>
<Class HashCode="-439631396">
<Address />
</Class>
<Class HashCode="307960707">
<Person />
</Class>
</Person>
</Class>
I want to be able to iterate only elements with XMLReader in the order they appear, which means class->Person-> class->FullName ,etc..
I was trying to navigate with methods like XMLReader.ReadStartElement() and it didn't work especially when I read a whitespaces like "\n" which appears to be an element also. :/
I was trying to bypass that whitespace with method XMLReader.Read() with no success.
Please help me understand how should I navigate that way.
XmlReader constructor has an overload that takes an XmlReaderSettings object. The XmlReaderSettings object has an IgnoreWhitespace property.
In order to read only the next elements you can implement an extension method on XmlReader.
Here's an example:
public static class ExtensionMethods
{
public static bool ReadNextElement(this XmlReader reader)
{
while (reader.Read())
if (reader.NodeType == XmlNodeType.Element)
return true;
return false;
}
}
And here's a little console application that will demonstrate this:
public class Program
{
public static void Main(string[] args)
{
var settings = new XmlReaderSettings();
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
settings.IgnoreProcessingInstructions = true;
var reader = XmlReader.Create("XMLFile1.xml", settings);
while (reader.ReadNextElement())
Console.WriteLine(reader.Name);
}
}

Categories

Resources