基于带点的文本构建分层HTML列表

本文关键字:分层 HTML 列表 构建 文本 于带点 | 更新日期: 2023-09-27 18:15:38

我正在寻找一种算法,它将转换像下面这样的数据结构,其中每个级别由点分隔:

child1
child1.child9
child4.child10.child11
child4.child10.child12

变成一个有效的HTML层次列表元素,如下所示:

<ul>
<li>child1
    <ul><li>child9</li></ul></li>
<li>child4
    <ul><li>child10
        <ul><li>child11</li><li>child12</li></ul></li></ul></li>
</ul>

有什么建议吗?

更新

问题从这种结构(下面)很容易构建层次列表

child
child.child1
child.child2
child.child2.child3

但是结构是

child.child2.child3
child7
child10.child14.child15
child10.child14.child16

所以我没有单独的行来构建父元素:(我必须从一行构建树,如果没有父

基于带点的文本构建分层HTML列表

您可以将列表转换为矩阵,然后使用分组/递归。这里有一个例子。它不能很好地打印HTML,但它应该给出正确的结果。

    static void Main(string[] args)
    {
        var list = new List<String>()
        {
            "child.child2.child3",
            "child7",
            "child10.child14.child15",
            "child10.child14.child16"
        };
        var matrix = new List<List<String>>();
        foreach (var line in list)
        {
            matrix.Add(line.Split('.').ToList());
        }
        StringBuilder html = new StringBuilder();
        WriteLevel(html, matrix, 0);
        Console.WriteLine(html.ToString());
    }
    static void WriteLevel(StringBuilder html, List<List<String>> matrix, int level)
    {
        var nodes = from node in matrix
                    where node.Count > level
                    group node by node[level] into grouping
                    select grouping;
        if (nodes.Count() > 0)
        {
            html.Append("<ul>");
            foreach (var node in nodes)
            {
                html.Append("<li>");
                html.Append(node.Key);
                WriteLevel(html, node.ToList(), level + 1);
                html.Append("</li>");
            }
            html.Append("</ul>");
        }
    }
using System;
using System.Xml;
using System.Collections.Generic;
class Sample{
    static void Main(string[] args){
        var doc = new XmlDocument();
        doc.LoadXml(@"
            <!DOCTYPE root [
              <!ELEMENT root (ul*) > 
              <!ELEMENT ul (li+) > 
              <!ELEMENT li ANY >
              <!ATTLIST root id ID #REQUIRED>
              <!ATTLIST li   id ID #REQUIRED>]>
            <root id='root'></root>");
        var relation = new List<String>(){
            "child.child2.child3",
            "child7",
            "child10.child14.child15",
            "child10.child14.child16"
        };
/* output(by hand made pretty):
  <ul>
    <li>child<ul><li>child2<ul><li>child3</li></ul></li></ul></li>
    <li>child7</li>
    <li>child10<ul><li>child14<ul><li>child15</li><li>child16</li></ul></li></ul></li>
  </ul>
*/
/*
        var relation = new List<String>(){
            "child1",
            "child1.child9",
            "child4.child10.child11",
            "child4.child10.child12"
        };
        var relation = new List<String>(){
            "child",
            "child.child1",
            "child.child2",
            "child.child2.child3"
        };
*/
        foreach(var path in relation){
            MakeTree(doc, path);
        }
        DeleteId(doc.DocumentElement);
        string result = doc.DocumentElement.InnerXml;
        Console.WriteLine(result);
//      doc.Save(Console.Out);
    }
    static void MakeTree(XmlDocument doc, string path){
        string parent = "root";
        foreach(var node in path.Split('.')){
            AppendChild(doc, parent, node);
            parent = node;
        }
    }
    static void DeleteId(XmlElement el){
        el.RemoveAttribute("id");
        if(el.HasChildNodes){
            foreach(XmlNode node in el.ChildNodes){
                if(node.NodeType == XmlNodeType.Element){
                    DeleteId((XmlElement)node);
                }
            }
        }
    }
    static void AppendChild(XmlDocument doc, string parent, string child){
        var childElement = doc.GetElementById(child);
        if(childElement == null){
            var li   = doc.CreateElement("li");
            var text = doc.CreateTextNode(child);
            li.SetAttribute("id", child);
            li.AppendChild(text);
            var parentElement = doc.GetElementById(parent);
            if(parent == "root"){
                if(parentElement.HasChildNodes){
                    parentElement.FirstChild.AppendChild(li);
                } else {
                    var ul   = doc.CreateElement("ul");
                    ul.AppendChild(li);
                    parentElement.AppendChild(ul);
                }
            } else {
                if(parentElement.LastChild.NodeType == XmlNodeType.Text){
                    var ul   = doc.CreateElement("ul");
                    ul.AppendChild(li);
                    parentElement.AppendChild(ul);
                } else {
                    parentElement.LastChild.AppendChild(li);
                }
            }
        }
    }
}