Как сериализовать TreeView в XML и десериализовать XML обратно в TreeView?

Древовидное представление xml

После загрузки элементов и атрибутов приведенного ниже XML-файла в древовидное представление узлы редактируются, и древовидное представление сохраняется в том же XML-файле. Все элементы и атрибуты должны быть сохранены. Однако атрибуты только вложенных элементов исчезают при сохранении. После сохранения все атрибуты элементов d & e теряются! Это связано с тем, что я не могу получить значения атрибутов, хранящиеся в свойстве тега в функции addTreeNode (см. Встроенные комментарии). Кто-нибудь знает, как проще или чище добиться этого? Предоставление фрагментов кода было бы полезно.

Структура XML:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <a axa="1" axb="2" axc="3">content_of_tag _a</a>
  <b bxa="10" bxb="20" bxc="30">content_of_tag_b</b>
  <c cxa="11" cxb="21" cxc="31">
  content_of_tag_c
      <d dxa="101" dxb="201" dxc="301">
      content_of_tag_d
          <e exa="110" exb="210" exc="310">
          content_of_tag_e
          </e>
      </d>
  </c>
</root>  

Код C#:

private void Xml2TreeNode(XElement xNode, TreeNode treeNode)
{
    if (xNode.HasElements) //if node has children
    {
        TreeNode tNode = null;
        int i = 0;
        foreach (XElement subNode in xNode.Elements())
        {
            if (subNode.Descendants().Count() > 0)
            {
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim());
                tn.Nodes.Add(new TreeNode(subNode.FirstNode.ToString().Trim()));
                treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //-------->this attribure values are NOT retrievable in saveNodes function!
                tNode = tn; //add child nodes
            }
            else
            {
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim()); //show name of a leaf node element
                tn.Nodes.Add(new TreeNode(subNode.Value.ToString().Trim())); //show value of above element as a child of its name
                treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrivable in saveNodes function
                tNode = treeNode.Nodes[i++]; //add sibling node
            }

            addTreeNode(subNode, tNode); //recursively add child nodes
        }
    }
}




private void TreeNode2Xml(TreeNodeCollection tnc)
{
    foreach (TreeNode node in tnc)
    {
        if (node.Nodes.Count > 0)
        {
            xr.WriteStartElement(node.Text);
            if (node.Tag != null) //attribures retrieved here
            {
                List<XAttribute> attributeList = node.Tag as List<XAttribute>;
                foreach (XAttribute attribute in attributeList)
                {
                    xr.WriteAttributeString(attribute.Name.ToString(), attribute.Value.ToString());
                }
            }
            saveNodes(node.Nodes);
            xr.WriteEndElement();
        }
        else //No child nodes, so we just write the text
        {
            xr.WriteString(node.Text);
        }
    }
}  



xr = new XmlTextWriter(filename, System.Text.Encoding.UTF8); //System.Text.Encoding.UTF8
xr.Formatting = Formatting.Indented;
xr.WriteStartDocument();
//Write our root node
xr.WriteStartElement(treeView1.Nodes[0].Text);
foreach (TreeNode node in tv.Nodes)
{
    **TreeNode2Xml(node.Nodes);**
}
//Close the root node
xr.WriteEndElement();
xr.Close();




xDoc = XDocument.Load(dlg.FileName);
treeView1.Nodes.Clear();
treeView1.Nodes.Add(new TreeNode(xDoc.Document.Root.Name.ToString().Trim()));
TreeNode tNode = new TreeNode();
tNode = (TreeNode)treeView1.Nodes[0];
**Xml2TreeNode(xDoc.Root, tNode);**
treeView1.ExpandAll();  

2 ответа

Решение

Я отвечаю на свой вопрос; это может помочь кому-то в будущем.

Решил проблему, внеся небольшие изменения в функцию Xml2TreeNode()

private void Xml2TreeNode(XElement xNode, TreeNode treeNode)
{
    if (xNode.HasElements) //if node has children
    {
        TreeNode tNode = null;
        int i = 0;
        foreach (XElement subNode in xNode.Elements())
        {
            if (subNode.Descendants().Count() > 0)
            {//handle non-leaf node
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim());
                tn.Nodes.Add(new TreeNode(subNode.FirstNode.ToString().Trim()));
                tn.Tag = treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrived in SaveNodes function
                tNode = tn; //add child nodes
            }
            else
            {//handle leaf node
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim()); //show name of a leaf node element
                tn.Nodes.Add(new TreeNode(subNode.Value.ToString().Trim())); //show value of above element as a child of its name
                tn.Tag = treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrived in SaveNodes function
                tNode = treeNode.Nodes[i++]; //add sibling node
            }

            Xml2TreeNode(subNode, tNode); //recursively add child nodes
        }
    }
}  



private void Xml2TreeNode(XElement xNode, TreeNode treeNode)
{
    if (xNode.HasElements) //if node has children
    {
        TreeNode tNode = null;
        int i = 0;
        foreach (XElement subNode in xNode.Elements())
        {
            if (subNode.Descendants().Count() > 0)
            {//handle non-leaf node
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim());
                ////tn.Nodes.Add(new TreeNode(subNode.FirstNode.ToString().Trim())); //adds extra element-value to node
                tn.Tag = treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrived in TreeNode2Xml function
                tNode = tn; //add child nodes
            }
            else
            {//handle leaf node
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim()); //show name of a leaf node element
                tn.Nodes.Add(new TreeNode(subNode.Value.ToString().Trim())); //show value of above element as a child of its name
                tn.Tag = treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrived in TreeNode2Xml function
                tNode = treeNode.Nodes[i++]; //add sibling node
            }

            Xml2TreeNode(subNode, tNode); //recursively add child nodes
        }
    }
}

Отличный пост загрузки и сохранения данных в виде дерева Пример загрузки / сохранения XML-Treeview

Сохранить код данных:

//We use this in the export and the saveNode 
//functions, though it's only instantiated once.
private StreamWriter sr;

public void exportToXml(TreeView tv, string filename) 
{
    sr = new StreamWriter(filename, false, System.Text.Encoding.UTF8);
    //Write the header
    sr.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
    //Write our root node
    sr.WriteLine("<" + treeView1.Nodes[0].Text + ">");
    foreach (TreeNode node in tv.Nodes)
    {
        saveNode(node.Nodes);
    }
    //Close the root node
    sr.WriteLine("</" + treeView1.Nodes[0].Text + ">");
    sr.Close();
}

private void saveNode(TreeNodeCollection tnc)
{
    foreach (TreeNode node in tnc)
    {
        //If we have child nodes, we'll write 
        //a parent node, then iterrate through
        //the children
        if (node.Nodes.Count > 0)
        {
            sr.WriteLine("<" + node.Text + ">");
            saveNode(node.Nodes);
            sr.WriteLine("</" + node.Text + ">");
        } 
        else //No child nodes, so we just write the text
            sr.WriteLine(node.Text);
    }
}

Загрузить данные

//Open the XML file, and start to populate the treeview
private void populateTreeview()
{
    OpenFileDialog dlg = new OpenFileDialog();
    dlg.Title = "Open XML Document";
    dlg.Filter = "XML Files (*.xml)|*.xml";
    dlg.FileName = Application.StartupPath + "\\..\\..\\example.xml";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        try
        {
            //Just a good practice -- change the cursor to a 
            //wait cursor while the nodes populate
            this.Cursor = Cursors.WaitCursor;
            //First, we'll load the Xml document
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(dlg.FileName);        
            //Now, clear out the treeview, 
            //and add the first (root) node
            treeView1.Nodes.Clear();
            treeView1.Nodes.Add(new 
              TreeNode(xDoc.DocumentElement.Name));
            TreeNode tNode = new TreeNode();
            tNode = (TreeNode)treeView1.Nodes[0];
            //We make a call to addTreeNode, 
            //where we'll add all of our nodes
            addTreeNode(xDoc.DocumentElement, tNode);
            //Expand the treeview to show all nodes
            treeView1.ExpandAll();    
        }
        catch(XmlException xExc) 
          //Exception is thrown is there is an error in the Xml
        {
            MessageBox.Show(xExc.Message);
        }
        catch(Exception ex) //General exception
        {
            MessageBox.Show(ex.Message);
        }
        finally
        {
            this.Cursor = Cursors.Default; //Change the cursor back
        }
    }
}
//This function is called recursively until all nodes are loaded
private void addTreeNode(XmlNode xmlNode, TreeNode treeNode)
{
    XmlNode xNode;
    TreeNode tNode;
    XmlNodeList xNodeList;
    if (xmlNode.HasChildNodes) //The current node has children
    {
        xNodeList = xmlNode.ChildNodes;
        for(int x=0; x<=xNodeList.Count-1; x++) 
          //Loop through the child nodes
        {
            xNode = xmlNode.ChildNodes[x];
            treeNode.Nodes.Add(new TreeNode(xNode.Name));
            tNode = treeNode.Nodes[x];
            addTreeNode(xNode, tNode);
        }
    }
    else //No children, so add the outer xml (trimming off whitespace)
        treeNode.Text = xmlNode.OuterXml.Trim();
}
Другие вопросы по тегам