Reading an XML file into a TreeView - c#

I am trying to load an XML file onto my GUI using a TreeView control.
However, I am using a proprietary layout for my XML file.
The XML is structured like this:
<ConfiguratorConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Section>
<Class ID="Example" Name="CompanyName.Example" Assembly="Example.dll">
<Interface>
<Property Name="exampleProperty1" Value="exampleValue" />
<Property Name="exampleProperty2" Value="exampleValue" />
<Property Name="exampleProperty3" Value="exampleValue" />
</Interface>
</Class>
</Section>
</ConfiguratorConfig>
I'd like the output to be structured like:
Class "Example"
Property "exampleProperty1"
Property "exampleProperty2"
Property "exampleProperty3"
I'm totally new to using XML. I've been searching the web for the past few hours, and none of the results have helped. Some have come close, but perhaps properties won't show up, or node's names won't display, etc.
I'm writing in c# in Visual Studio 2005.
Thanks for the help!

You can iterate through nodes using XmlDocument, you can put this demo in a Main method of a console application:
string xml = #"<ConfiguratorConfig xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
<Section>
<Class ID=""Example"" Name=""CompanyName.Example"" Assembly=""Example.dll"">
<Interface>
<Property Name=""exampleProperty1"" Value=""exampleValue"" />
<Property Name=""exampleProperty2"" Value=""exampleValue"" />
<Property Name=""exampleProperty3"" Value=""exampleValue"" />
</Interface>
</Class>
</Section></ConfiguratorConfig>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
foreach (XmlNode _class in doc.SelectNodes(#"/ConfiguratorConfig/Section/Class"))
{
string name = _class.Attributes["ID"].Value;
Console.WriteLine(name);
foreach (XmlElement element in _class.SelectNodes(#"Interface/Property"))
{
if (element.HasAttribute("Name"))
{
string nameAttributeValue = element.Attributes["Name"].Value;
Console.WriteLine(nameAttributeValue);
}
}
}
If you're using version of .NET higher than 3.0 you can use XDocument class (recommended if you can choose).
XDocument xdoc = XDocument.Parse(xml);
foreach (XElement _class in xdoc.Descendants("Class"))
{
string name = _class.Attribute("ID").Value;
Console.WriteLine(name);
foreach (XElement element in _class.Descendants("Property"))
{
XAttribute attributeValue = element.Attribute("Name");
if (attributeValue != null)
{
string nameAttributeValue = attributeValue.Value;
Console.WriteLine(nameAttributeValue);
}
}
}

Related

SelectNodes brings back to many results

Loading this XML works
<?xml version="1.0" encoding="utf-8" ?>
<export>
<document ID="uuuid_1">
<Property Name="PersonName" Value="bob"></Property>
<Property Name="FileName" Value="bob.tif">
<Reference Link="company\export\uuuid_1_423_bob.tif"/>
</Property>
<Property Name="FileName" Value="bob.txt">
<Reference Link="company\export\uuuid_1_123_bob.txt"/>
</Property>
<Property Name="FileName" Value="bob.tif">
<Reference Link="company\export\uuuid_1_123_bob.tif"/>
</Property>
</document>
<document ID="uuuid_2">
<Property Name="PersonName" Value="mary"></Property>
<Property Name="FileName" Value="mary.tif">
<Reference Link="company\export\uuuid_2_456_mary.tif"/>
</Property>
<Property Name="FileName" Value="mary.txt">
<Reference Link="company\export\uuuid_2_567_mary.txt"/>
</Property>
</document>
</export>
with that method
static void XmlLoader(string xml_path)
{
Console.WriteLine("Loading " + xml_path);
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(xml_path);
XmlNodeList nodes_document = xmldoc.SelectNodes("/export/document");
foreach (XmlNode nd in nodes_document)
{
string Id = nd.Attributes["ID"].Value.ToString();
string name = nd.SelectSingleNode("//Property[#Name='PersonName']/#Value").InnerText;
XmlNodeList files = nd.SelectNodes("//Property[#Name='FileName'][contains(#Value,'.tif')]/Reference/#Link");
Console.WriteLine(files.ToString());
}
}
The XmlNodeList inside the iteration of documents brings back a list of ALL tifs in the XML not only the ones from the nd Node.
How would I correctly use Xpath to select a list inside the nd element?
Just remove "//" from SelectNodes and SelectSingleNode. The double slash is parsing the complete xml
static void XmlLoader(string xml_path)
{
Console.WriteLine("Loading " + xml_path);
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(xml_path);
XmlNodeList nodes_document = xmldoc.SelectNodes("/export/document");
foreach (XmlNode nd in nodes_document)
{
string Id = nd.Attributes["ID"].Value.ToString();
string name = nd.SelectSingleNode("Property[#Name='PersonName']/#Value").InnerText;
XmlNodeList files = nd.SelectNodes("Property[#Name='FileName'][contains(#Value,'.tif')]/Reference/#Link");
Console.WriteLine(files.ToString());
}
}

Selecting a xml Node from and adding more nodes based on its value using xslt and c# [duplicate]

This question already has answers here:
How to iterate over IDREFS values in XSLT 1.0?
(2 answers)
Closed 3 years ago.
I have a problem in writing an xslt as im a beginner to xslt. The scenario is as below :
From the Property with attribute name "Value" , i should check if it contains '^' symbol. If it contains, i should add more Property tags, for each of the value split by '^'.
I tried doing it in xslt , but went nuts on the output which i got.
//logic
Tried this, but could'nt figure out what logic needs to go inside the xsl foreach to add new property tags.
Please include any xslt resources where i can learn it.
Can i do the c# xml stuff's like
Function()
{
var splitstring[]=string.Split('^');
XmlAttribute.SetAttribute('Val1','splitstring[0]');
XmlAttribute.SetValue('Val2',splitstring[1]);
}
Input xml :
<Observation>
<Property Name="Type" Value="1234"/>
<Property Name="Code" Value="CodeA"/>
<Property Name="Value1" Value="12345^Val1^6789"/>
<Property Name="Unit" Value=""/>
<Property Name="Status" Value=""/>
</Observation>
This is the input xml
Output xml :
<Observation>
<Property Name="Type" Value="1234"/>
<Property Name="Code" Value="CodeA"/>
<Property Name="Value1" Value="12345"/>
<Property Name="Value2" Value="Val1"/>
<Property Name="Value3" Value="6789"/>
<Property Name="Unit" Value=""/>
<Property Name="Status" Value=""/>
</Observation>
How can i integrate a c# code (because it's easy) or an xslt logic to make this happen?
Try Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication137
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<XElement> properties = doc.Descendants("Property").ToList();
for (int i = properties.Count - 1; i >= 0; i-- )
{
XElement property = properties[i];
string value = (string)property.Attribute("Value");
if (value.Contains("^"))
{
property.ReplaceWith(ReplaceElement(property));
}
}
}
static List<XElement> ReplaceElement(XElement element)
{
List<XElement> elements = new List<XElement>();
string name = (string)element.Attribute("Name");
string baseName = Regex.Match(name, #"[^\d]+").Value;
string value = (string)element.Attribute("Value");
string[] splitValues = value.Split(new char[] { '^' }).ToArray();
for (int i = 1; i <= splitValues.Length; i++)
{
elements.Add(new XElement("Property", new XAttribute[] {
new XAttribute("Name", baseName + i.ToString()),
new XAttribute("Value", splitValues[i - 1])
}));
}
return elements;
}
}
}

XDocument losing line number

I'm using XDocument to parse my XML File, but when I try to read the line number of a XNode or a XElement, it's always equal to zero.
I tried different ways to parse it:
foreach (XElement node in xDoc.Root.Descendants("nodeName"))
or
xDoc.XPathSelectElement("nodeName")
and each time ((IXmlLineInfo)node).LineNumber returns 0!
I'm using a XmlNamespaceManager.
Did I miss something?
Thanks in advance!
Edit :
Here is the concerned Xml as asked.
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance">
<CstmrDrctDbtInitn>
<GrpHdr>
<MsgId>XXXXXXXXX</MsgId>
<CreDtTm>2013-06-12T00:00:00</CreDtTm>
<NbOfTxs>1</NbOfTxs>
<CtrlSum>136.82</CtrlSum>
<InitgPty>
<Nm>name</Nm>
<Id>
<OrgId>
<Othr>
<Id>XXXXXXXXX</Id>
</Othr>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<PmtInf>
<PmtInfId>275-20130612-FIRST</PmtInfId>
<PmtMtd>DD</PmtMtd>
<BtchBookg>true</BtchBookg>
<NbOfTxs>1</NbOfTxs>
<CtrlSum>136.82</CtrlSum>
<PmtTpInf>
<SvcLvl>
<Cd>SEPA</Cd>
</SvcLvl>
<LclInstrm>
<Cd>CORE</Cd>
</LclInstrm>
<SeqTp>RCUR</SeqTp>
</PmtTpInf>
<ReqdColltnDt>2013-06-05</ReqdColltnDt>
<Cdtr>
<Nm>name</Nm>
<PstlAdr>
<Ctry>BE</Ctry>
<AdrLine>XXXXXXXXX</AdrLine>
<AdrLine>XXXXXXXXX</AdrLine>
</PstlAdr>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>XXXXXXXXX</IBAN>
</Id>
</CdtrAcct>
<CdtrAgt>
<FinInstnId>
<BIC>XXXXXXXXX</BIC>
</FinInstnId>
</CdtrAgt>
<ChrgBr>SLEV</ChrgBr>
<CdtrSchmeId>
<Id>
<PrvtId>
<Othr>
<Id>XXXXXXXXX</Id>
<SchmeNm>
<Prtry>SEPA</Prtry>
</SchmeNm>
</Othr>
</PrvtId>
</Id>
</CdtrSchmeId>
<DrctDbtTxInf>
<PmtId>
<InstrId>XXXXXXXXX</InstrId>
<EndToEndId>XXXXXXXXX</EndToEndId>
</PmtId>
<InstdAmt Ccy="EUR">136.82</InstdAmt>
<DrctDbtTx>
<MndtRltdInf>
<MndtId>XXXXXXXXX</MndtId>
<DtOfSgntr>2009-10-31</DtOfSgntr>
<AmdmntInd>false</AmdmntInd>
<AmdmntInfDtls>
<AmdmntInd>yellowland</AmdmntInd>
<OrgnlMndtId>XXXXXXXXX</OrgnlMndtId>
<OrgnlCdtrSchmeId>
<Id>
<PrvtId>
<Othr>
<Id>XXXXXXXXX</Id>
<SchmeNm>
<Prtry>SEPA</Prtry>
</SchmeNm>
</Othr>
</PrvtId>
</Id>
</OrgnlCdtrSchmeId>
</AmdmntInfDtls>
</MndtRltdInf>
</DrctDbtTx>
<DbtrAgt>
<FinInstnId>
<BIC>XXXXXXXXX</BIC>
</FinInstnId>
</DbtrAgt>
<Dbtr>
<Nm>TEST</Nm>
<PstlAdr>
<Ctry>BE</Ctry>
<AdrLine>XXXXXXXXX</AdrLine>
<AdrLine>XXXXXXXXX</AdrLine>
</PstlAdr>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>XXXXXXXXX</IBAN>
</Id>
</DbtrAcct>
<RmtInf>
<Ustrd>test</Ustrd>
</RmtInf>
</DrctDbtTxInf>
</PmtInf>
</CstmrDrctDbtInitn>
</Document>
The LineInformations are not always loaded, when you load xml via XDocument.
You need to specify that you also want to load the LineInformation when you load the XML. That is done by using one of the Load methods that you can pass in a value of LoadOptions of the XDocument class.
var document = XDocument.Load(file, LoadOptions.SetLineInfo);
From here
XDocument xdoc = XDocument.Load(file);
IEnumerable<XElement> nodes = xdoc.Descendants("nodeName");
foreach (XElement node in nodes)
{
IXmlLineInfo info = node;
int lineNumber = info.LineNumber;
}

How to get value of some object in XML string in C#?

I have this XML String :
<RESPONSE>
<SINGLE>
<KEY name="sitename">
<VALUE>Stackoverflow</VALUE>
</KEY>
<KEY name="username">
<VALUE>this value</VALUE>
</KEY>
</SINGLE>
</RESPONSE>
How to get value from Key that name "username" ? I want to get value of "this value" in my code. I try deserialized and any other code but it doesnt work. Please help me, thanks :D
Edit:
I tried using this code :
XDocument doc = XDocument.Load( "myXML.xml" );
var keys = doc.Descendants( "KEY" );
foreach ( var VALUE in keys )
{
Console.WriteLine( VALUE.Value );
}
But how did I get the Value only from KEY that named "Username" ? Thanks :))
You can probably use an xpath to do this. The following is an example XPath that will provide a node with name matching "sitename":
//KEY[#name="sitename"]
You can modify this slightly to find all nodes with a "name" attribute or to just find specific names. For more examples of how to use XPath see the MSDN site for XPath. The following is a snippet of C# code that shows you how to use this XPath (again, you can generalize for whatever XPath you need):
const string example_xml = "<RESPONSE> <SINGLE> <KEY name=\"sitename\"> <VALUE>Stackoverflow</VALUE> </KEY> <KEY name=\"username\"> <VALUE>this value</VALUE> </KEY> </SINGLE> </RESPONSE>";
// load
XmlDocument doc = new XmlDocument();
doc.LoadXml(example_xml);
// Query single or multiple nodes using the XPath, do what you want with this node!
var desiredNode = doc.SelectSingleNode("//KEY[#name=\"sitename\"]");
Best of luck!
For completeness here is a System.Xml.Linq version, with the foreachs and where's being System.Linq for good measure. This basically the questioner's attempt, with a where to filter according to attribute.
const string example_xml = "<RESPONSE> <SINGLE> <KEY name=\"sitename\"> <VALUE>Stackoverflow</VALUE> </KEY> <KEY name=\"username\"> <VALUE>this value</VALUE> </KEY> </SINGLE> </RESPONSE>";
XDocument doc = XDocument.Parse(example_xml);
var keys = doc.Descendants("KEY");
var userKeys = keys.Where(item => item.Attribute("name").Value == "username").ToList();
userKeys.ForEach(item => Console.WriteLine(item.Value));
Lets consider your xml document as XYZ.xml, then you may try below code if you are using C#, below is the example only
XmlDocument Doc = new XmlDocument();
Doc.Load(Server.MapPath(".../xyz.xml"));
XmlNodeList itemList = Doc.DocumentElement.SelectNodes("KEY");
foreach (XmlNode currNode in itemList)
{
string name = string.Empty;
XmlNode item = currNode.SelectSingleNode("KEY");
if(currNode["name"].InnerText == "username")//if you are aware of key name, use this condition
{
name = item.Attributes["name"].Value.ToString(); // or currNode["name"].InnerText;
}
}

Reading <property> tag

I was asked today to look at a new project - reading in some XML and doing some analysis. I know a little C#. I have gotten this far with this code that so far works. I get the 4 node lists successfully. I have a couple problems. First I am not sure how to access what is in the tag on any of the nodes in any of the lists. Second, I'd prefer to be able to use LINQ queries but XmlNodeList doesn't seem to support that syntax. In the sample XML below, I'd like to be able to get all the vdisks that belong to a particular IO Group or mdisk as determined by io_group_name or mdisk_grp_name property. Most of what I looked at gave examples for accessing the [Attribute] list and searches all used properties/atttributes interchanged.
What I tried is also below, it gave a null value exception. The Attributes list only has one attribute. I can't find any examples to do what I want and it isn't clear from inspecting the node in the debugger what I need to access to do what I want.
//this works
XmlTextReader reader = new XmlTextReader(_InputFile);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList clusterlist = doc.SelectNodes("//object[#type='cluster']");
XmlNodeList controllerlist = doc.SelectNodes("//object[#type='controller']");
XmlNodeList mdisklist = doc.SelectNodes("//object[#type='mdisk']");
XmlNodeList vdisklist = doc.SelectNodes("//object[#type='vdisk']");
// this did not work - got null value exception
foreach (XmlNode vdisknode in vdisklist)
{
string str = vdisknode.Attributes["mdisk_grp_name"].Value;
}
A sample of the XML:
<object type="vdisk">
<property name="id" value="0" />
<property name="name" value="nim01_vd06_gmt" />
<property name="IO_group_id" value="0" />
<property name="IO_group_name" value="ossvc06_iogrp0" />
<property name="status" value="online" />
<property name="mdisk_grp_id" value="0" />
<property name="mdisk_grp_name" value="T1_OSIBM06_MDG1" />
<property name="capacity" value="644245094400" />
<property name="type" value="striped" />
</object>
object node has only one attribute: type
string type = vdiskNode.Attributes["type"].Value;
property node has two attributes: name and value:
string name = propertyNode.Attributes["name"].Value;
string value = propertyNode.Attributes["value"].Value;
What you need I deem is to extend the XPath query:
"//object[#type='vdisk']/property[#name='mdisk_grp_name']/#value"
Or use LINQ to XML:
from obj in doc.Load(xml).Root.Elements("object")
where (string)obj.Attribute("type") == "vdisk"
from prop in obj.Elements("property")
//where (string)prop.Attribute("name") == name
select prop.Value

Categories