Как вывести файл Xml деревом в консоль с рекурсией. Вроде все читается, но вот как вывести именно деревом, как и сам файл Xml никак не соображу
А вам обязательно рекурсией? На сайте microsoft есть пример как вывести в строку как в [2], а в простейшем случае replace или regexp+replace все теги можно убрать.
2 ответа 2
Если вам не требуется специфический для класса XmlDocument функционал, то проще воспользоваться XDocument из пространства имен System.Xml.Linq . Это позволит получить более компактный код.
Для вывода на консоль в том виде, который вы указали есть три пути.
1. Рекурсивный обход дерева XML
Реализуется довольно просто:
static void Main(string[] args) < XElement doc = XElement.Load(@"H:\test.xml"); PrintElementV1(doc); Console.ReadKey(); >static void PrintElementV1(XElement elem) < if (elem.Elements().Count() >0) < Console.WriteLine(elem.Name); foreach (XElement e in elem.Elements()) < PrintElementV1(e); >> else < Console.WriteLine(": ", elem.Name, elem.Value); > >
Но вставить в этот вод избирательную нумерацию конкретных элементов без «костылей» не выйдет. «Костыль» для нумерации может выглядеть так:
static void PrintElementV1(XElement elem, int num) < if (elem.Elements().Count() >0) < Console.WriteLine(". ", num, elem.Name); int i = 1; foreach (XElement e in elem.Elements()) < PrintElementV1(e, i++); >> else < Console.WriteLine(": ", elem.Name, elem.Value); > >
При этом будут пронумерованы все элементы кроме тех, которые не содержат в себе других элементов.
2. Фиксированный обход дерева XML
С точки зрения дерева, рекурсия сохраняется, такова уж структура дерева, но если эта структура фиксирована и известна, то можно обойтись без рекурсивного вызова методов а использовать цепочку вызовов в цикле. Покажу на примере:
static void Main(string[] args) < XElement doc = XElement.Load(@"H:\test.xml"); Console.WriteLine(doc.Name); PrintCDList(doc); Console.ReadKey(); >static void PrintCDList(XElement elem) < int i = 1; foreach (XElement e in elem.Elements()) < Console.WriteLine(". ", i++, e.Name); PrintContent(e); > > static void PrintContent(XElement elem) < foreach (XElement e in elem.Elements()) < Console.WriteLine(": ", e.Name, e.Value); > >
как видите, рекурсия отсутствует, но если структура XML будет отличаться от заложенной в коде, «все превратится в тыкву» и будет давать неверные результаты.
3. Ручной парсинг
Можно выполнить всю работу руками, получив исходный текст XML в виде текста. Для этого можно воспользоваться любым известным вам способом получения текста из файла.
Далее к строке исходного XML текста применяем всевозможные регулярные выражения или другие известные вам способы преобразования строки до получения строки или массива строк нужного вида и выводим полученное.
Приводить код данного способа не стану, так как вариантов для подобного решения существует масса, а взглядов на то, как это сделать правильно еще больше. К тому же, я сильно сомневаюсь, что подобный вариант будет существенно производительнее чем два предыдущих, скорее наоборот.
Выбирайте какой вариант вам больше подходит =)
PS: Если важно использовать именно XmlDocument , пишите в комментарии, дополню соответствующим примером.
Источник
Рекурсивное сохранение TreeView в XML
Сохранение информации в XML является широко используемой технологией в программировании, это позволяет сохранять данные в удобном для обработки формате. Рекурсия в программировании используется для обхода древовидных структур, таких как деревья и связанные списки. В этой статье мы поговорим о рекурсивном сохранении TreeView в XML.
Treeview — это элемент управления, который является отображением структурированных данных в виде дерева. Элемент управления TreeView имеет вершину, с которой начинается дерево, и множество узлов подвершину.
Первым шагом будет создание базового класса для сохранения элементов TreeView в XML:
using System; using System.IO; using System.Reflection; using System.Text; using System.Windows.Forms; using System.Xml.Serialization; namespace TreeViewXmlSave < public class TreeViewXmlSave < public void SaveTreeView(TreeView treeView, string fileName) < using (FileStream stream = new FileStream(fileName, FileMode.Create)) < using (TextWriter writer = new StreamWriter(stream, Encoding.UTF8)) < XmlSerializer serializer = new XmlSerializer(typeof(TreeNodeCollection)); serializer.Serialize(writer, treeView.Nodes); >> > public void LoadTreeView(TreeView treeView, string fileName) < using (FileStream stream = new FileStream(fileName, FileMode.Open)) < XmlSerializer serializer = new XmlSerializer(typeof(TreeNodeCollection)); treeView.Nodes.Clear(); treeView.Nodes.AddRange((TreeNode[])serializer.Deserialize(stream)); >> > >
Здесь мы определяем два метода: SaveTreeView() для сохранения элементов TreeView в XML-документ, и LoadTreeView() — для загрузки сохраненных данных обратно в TreeView.
Теперь мы готовы реализовать рекурсивный алгоритм для сохранения данных TreeView в XML.
Давайте представим структуру TreeView:
TreeView | |--Node1 | |--Node1.1 | | |--Node1.1.1 | | |--Node1.1.2 | | | |--Node1.2 | |--Node2 | |--Node2.1 | |--Node2.2 | |--Node3
Определим структуру класса TreeNode для хранения данных узла TreeView:
[Serializable] public class TreeNode < public string Text < get; set; >public List Nodes < get; set; >>
Сохранение TreeView в XML заключается в рекурсивном обходе всех узлов и сохранении их в виде объектов TreeNode вместе со списками их дочерних узлов.
Вот как будет выглядеть рекурсивный алгоритм:
private TreeNode SaveNode(System.Windows.Forms.TreeNode node) < TreeNode treeNode = new TreeNode(); treeNode.Text = node.Text; foreach(System.Windows.Forms.TreeNode childNode in node.Nodes) < treeNode.Nodes.Add(SaveNode(childNode)); >return treeNode; > public void SaveTreeView(TreeView treeView, string fileName) < using (FileStream stream = new FileStream(fileName, FileMode.Create)) < using (TextWriter writer = new StreamWriter(stream, Encoding.UTF8)) < XmlSerializer serializer = new XmlSerializer(typeof(List)); List treeNodes = new List(); foreach (System.Windows.Forms.TreeNode node in treeView.Nodes) < treeNodes.Add(SaveNode(node)); >serializer.Serialize(writer, treeNodes); > > >
Как видим, метод SaveNode() рекурсивно вызывает сам себя для сохранения дочерних узлов. Метод SaveTreeView() просто обходит все корневые узлы TreeView и сохраняет их в List. Затем объекты List сериализуются в XML с использованием класса XmlSerializer.
Чтобы загрузить сохраненные данные из XML обратно в TreeView, нужно выполнить обратный процесс — рекурсивно создавать узлы и их дочерние узлы из данных, хранящихся в List. Возвращаемые объекты TreeNode добавляются в свойство Nodes объекта TreeNode предыдущего уровняиерархии. Вот как реализовать метод LoadTreeView():
private void LoadNode(System.Windows.Forms.TreeNode treeNode, TreeNode node) < foreach (TreeNode childNode in node.Nodes) < System.Windows.Forms.TreeNode tNode = new System.Windows.Forms.TreeNode(); tNode.Text = childNode.Text; treeNode.Nodes.Add(tNode); LoadNode(tNode, childNode); >> public void LoadTreeView(TreeView treeView, string fileName) < using (FileStream stream = new FileStream(fileName, FileMode.Open)) < XmlSerializer serializer = new XmlSerializer(typeof(List)); List treeNodes = (List)serializer.Deserialize(stream); foreach (TreeNode node in treeNodes) < System.Windows.Forms.TreeNode tNode = new System.Windows.Forms.TreeNode(); tNode.Text = node.Text; treeView.Nodes.Add(tNode); LoadNode(tNode, node); >> >
Рекурсивный метод LoadNode() вызывается для каждого узла TreeView и его дочерних узлов в цикле foreach(). В методе LoadNode() мы создаем новый узел System.Windows.Forms.TreeNode и добавляем его в свойство Nodes объекта System.Windows.Forms.TreeNode предыдущего уровня иерархии. Затем мы рекурсивно вызываем этот же метод для сохранения дочерних узлов.
Рекурсивное сохранение TreeView в XML является мощным инструментом для создания приложений, использующих TreeView. Надеюсь, что данная статья помогла вам понять, как это может быть реализовано на практике.
Источник
рекурсия — Построение дерева из XML-файла с использованием RapidXML и переполнения стека
Для проекта для моего класса C ++ я должен проанализировать и XML-файл и построить из него двоичное дерево. Файл гораздо более плотный, чем этот, но макет выглядит следующим образом:
Sea Creature Fish swordfish grouper Mammal dolphin whale Land animal Mammal dog cat Bird blue jay robin
Мне трудно понять, как проанализировать эти данные, чтобы я мог построить дерево. Я думал, что могу использовать рекурсию для каждой ветви, но я могу получить только одного ребенка. Кто-то намекнул на использование очереди для помещения данных в древовидную структуру, но я не совсем уверен, как можно пройти все уровни дерева, используя очередь. Я чувствую, что рекурсия — это самый простой способ разбора данных для каждой ветви, но я просто не могу понять, как правильно реализовать рекурсивный метод. Вот метод, который я пытался использовать. Я прошел в корневой узел первым:
void loop(xml_node<> *species) < Node t1 = *new Node(); xml_node<>* name_node = species->first_node("name"); if(name_node != 0) < t1.setName(name_node->value()); cout value() xml_node<> * child = species->first_node("species"); if(child != 0) < cout first_node("name")->value() first_node()->next_sibling() != 0) < loop(child->first_node()->next_sibling()); xml_node<> * child2 = child->next_sibling(); cout first_node()->value() first_node()->next_sibling()); > > >
Он проходит только через первого потомка каждого узла, возвращающего Морское Существо
Рыба
рыба-меч
Сухопутное животное
млекопитающее
собака
Я был бы очень признателен за любые указатели в правильном направлении. Спасибо!
Решение
Чтобы охватить все узлы в этом файле, вам нужно посмотреть на каждый узел дети И его братья и сестры. Вы, кажется, понимаете это.
Ваш рекурсивный подход является подходящим выбором для того, чтобы добраться до детей. Кажется, это работает. Каждый рекурсивный вызов loop идет на один уровень глубже в детей. (Тот, кто сказал вам использовать «очередь», возможно, имел в виду «стек» … а рекурсия неявно использует стек. Стек вызовов.)
Это братья и сестры, которые скучают. И поскольку рекурсия используется для углубления в дерево XML, это, вероятно, не будет решено с помощью большей рекурсии.
Посмотрите на эту часть кода вашего кода:
xml_node<> * child = species->first_node("species"); if(child != 0) < cout first_node("name")->value()
Здесь вы найдете первого родного брата, такого как "swordfish" ,
Попробуйте изменить это if оператор в цикле, поэтому содержащаяся логика выполняется на всех братьев и сестер, а не только первый.
Другие решения
Я знаю, что на этот вопрос уже дан ответ, но я просто хочу добавить полезную подсказку.
Вместо того чтобы использовать рекурсию, вы можете использовать стеки / очереди для анализа этого XML-файла для построения своей «древовидной» структуры.
Если вы хотите придерживаться рекурсии, убедитесь, что все дочерние элементы указывают на одного и того же родителя, иначе структура дерева будет неправильной.
Источник