Using C# I have an XML file containing a folders structure, the user selects the main project folder then the system begins checking the sub-folders in the main project folder based on the structure of the XML file. The folder structure is dynamic as the admin of the application can add/remove/modify a folder within the structure by changing the XML file.
How do I loop through the XML, I tried using XmlDocument to get the full directory pathbut I read about using XDocument for better result but my knowledge of XML is still basic.
The XML file structure is:
<?xml version="1.0" encoding="utf-8" ?>
<dir name="Site Documents">
<dir name="External">
<dir name="Mechanical">
<dir name="01. Submittals">
<dir name="1. Sent">
</dir>
<dir name="2. Received" />
</dir>
<dir name="02. Drawings">
<dir name="1. Sent">
</dir>
<dir name="2. Received" />
</dir>
<dir name="03. MIR">
<dir name="1. Sent">
</dir>
<dir name="2. Received" />
</dir>
<dir name="04. IR">
<dir name="1. Sent">
</dir>
<dir name="2. Received" />
</dir>
</dir>
<dir name="Electrical">
<dir name="01. Submittals">
<dir name="1. Sent">
</dir>
<dir name="2. Received" />
</dir>
<dir name="02. Drawings">
<dir name="1. Sent">
</dir>
<dir name="2. Received" />
</dir>
<dir name="03. MIR">
<dir name="1. Sent">
</dir>
<dir name="2. Received" />
</dir>
<dir name="04. IR">
<dir name="1. Sent">
</dir>
<dir name="2. Received" />
</dir>
</dir>
</dir>
<dir name="Internal">
<dir name="01. PR">
<dir name="1. MECH">
</dir>
<dir name="2. ELEC" />
</dir>
<dir name="02. PO">
</dir>
<dir name="03. SRF">
</dir>
<dir name="04. RMR" />
</dir>
</dir>
EDIT -- 1
I tried using this test code to get the path of the node and sub-node
private void button2_Click(object sender, EventArgs e)
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(@"C:\Users\John_Doe\_data\directory_hirarchy.xml");
XmlNodeList xmlFolderName = xDoc.SelectNodes("//dir");
MessageBox.Show(xmlFolderName.Count.ToString());
string finalText = "";
for (int ctr = 0; ctr < xmlFolderName.Count; ctr++)
{
string DocFolder = xmlFolderName[ctr].Attributes["name"].InnerText;
finalText = finalText + DocFolder + "\r\n";
}
txtDisplay.Text = finalText; // Test text box for Output Result
}
The output of the text box is:
Site Documents
External
Mechanical
01. Submittals
1. Sent
2. Received
02. Drawings
1. Sent
2. Received
03. MIR
1. Sent
2. Received
04. IR
1. Sent
2. Received
Electrical
01. Submittals
1. Sent
2. Received
02. Drawings
1. Sent
2. Received
03. MIR
1. Sent
2. Received
04. IR
1. Sent
2. Received
Internal
01. PR
1. MECH
2. ELEC
02. PO
03. SRF
04. RMR
Solved by Daisy Shipton
using System;
using System.Linq;
using System.Xml.Linq;
class Program
{
static void Main()
{
var doc = XDocument.Load("test.xml");
var directories = doc.Descendants("dir");
foreach (var dir in directories)
{
var parts = dir
.AncestorsAndSelf() // All the ancestors of this element, and itself
.Reverse() // Reversed (so back into document order)
.Select(e => e.Attribute("name").Value); // Select the name
var path = string.Join("/", parts);
Console.WriteLine(path);
}
}
}
There are two options here:
The first is probably simplest to understand, and yes, using LINQ to XML makes life simpler.
using System;
using System.Xml.Linq;
class Program
{
static void Main()
{
var doc = XDocument.Load("test.xml");
PrintDirectories(doc, null);
}
static void PrintDirectories(XContainer parent, string path)
{
foreach (XElement element in parent.Elements("dir"))
{
string dir = element.Attribute("name").Value;
string fullPath = path == null ? dir : $"{path}/{dir}";
Console.WriteLine(fullPath);
PrintDirectories(element, fullPath);
}
}
}
The non-recursive approach is about the same size, but possibly harder to understand if you're not familiar with LINQ:
using System;
using System.Linq;
using System.Xml.Linq;
class Program
{
static void Main()
{
var doc = XDocument.Load("test.xml");
var directories = doc.Descendants("dir");
foreach (var dir in directories)
{
var parts = dir
.AncestorsAndSelf() // All the ancestors of this element, and itself
.Reverse() // Reversed (so back into document order)
.Select(e => e.Attribute("name").Value); // Select the name
var path = string.Join("/", parts);
Console.WriteLine(path);
}
}
}