如何根据起始文本将相同级别的元素制作成嵌套列表。

huangapple go评论53阅读模式
英文:

How to make nested list from same level elements, based on start-text

问题

我正在尝试创建一个嵌套列表,基于列表项(相同级别),但具有不同的标签文本,这将成为每个列表项的起始文本。我已经使用一些正则表达式替换来满足嵌套要求。我假设我的代码不足以满足分组和嵌套的要求。

IN.xml:

<?xml version="1.0" encoding="UTF-8"?>
<article>
   <p>The Simple list sample</p>
   <list-item>1. First</list-item>
   <list-item>2. Second</list-item>
   <list-item>3. Third</list-item>
   <p>The Nested list sample</p>
   <list-item>1. FirstLevel First Text</list-item>
   <list-item>1.1 SecondLevel First Text</list-item>
   <list-item>1.1.1 ThirdLevel First Text</list-item>
   <list-item>1.1.2 ThirdLevel Second Text</list-item>
   <list-item>1.2 SecondLevel Second Text</list-item>
   <list-item>2. FirstLevel Second Text</list-item>
   <list-item>2.1 SecondLevel First Text</list-item>
   <list-item>2.2 SecondLevel Second Text</list-item>
   <list-item>3. FirstLevel Third Text</list-item>
   <list-item>4. FirstLevel Fourth Text</list-item>
</article>

C#(尝试的代码):

// 这里是你的C#代码部分

Required XML:

<?xml version="1.0" encoding="UTF-8"?>
<article>
   <p>The Simple list sample</p>
   <List1>
      <list-item>1. First</list-item>
      <list-item>2. Second</list-item>
      <list-item>3. Third</list-item>
   </List1>
   <p>The Nested list sample</p>
   <List1>
      <list-item>1. FirstLevel First Text
         <List2>
            <list-item>1.1 SecondLevel First Text
               <List3>
                  <list-item>1.1.1 ThirdLevel First Text</list-item>
                  <list-item>1.1.2 ThirdLevel Second Text</list-item>
               </List3>
            </list-item>
            <list-item>1.2 SecondLevel Second Text</list-item>
         </List2>
      </list-item>
      <list-item>2. FirstLevel Second Text
         <List2>
            <list-item>2.1 SecondLevel First Text</list-item>
            <list-item>2.2 SecondLevel Second Text</list-item>
         </List2>
      </list-item>
      <list-item>3. FirstLevel Third Text</list-item>
      <list-item>4. FirstLevel Fourth Text</list-item>
   </List1>
</article>

这是你要的翻译结果。如果需要进一步帮助,请随时告诉我。

英文:

I'm trying to a make nested list based on list-item's (same level), but having different label text, which will start-text of each list-item. I have done with some regex replaces to meet the nesting. I assume my code is not up to mark to meet the grouping|nesting.

IN.xml:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;article&gt;
   &lt;p&gt;The Simple list sample&lt;/p&gt;
   &lt;list-item&gt;1. First&lt;/list-item&gt;
   &lt;list-item&gt;2. Second&lt;/list-item&gt;
   &lt;list-item&gt;3. Third&lt;/list-item&gt;
   &lt;p&gt;The Nested list sample&lt;/p&gt;
   &lt;list-item&gt;1. FirstLevel First Text&lt;/list-item&gt;
   &lt;list-item&gt;1.1 SecondLevel First Text&lt;/list-item&gt;
   &lt;list-item&gt;1.1.1 ThirdLevel First Text&lt;/list-item&gt;
   &lt;list-item&gt;1.1.2 ThirdLevel Second Text&lt;/list-item&gt;
   &lt;list-item&gt;1.2 SecondLevel Second Text&lt;/list-item&gt;
   &lt;list-item&gt;2. FirstLevel Second Text&lt;/list-item&gt;
   &lt;list-item&gt;2.1 SecondLevel First Text&lt;/list-item&gt;
   &lt;list-item&gt;2.2 SecondLevel Second Text&lt;/list-item&gt;
   &lt;list-item&gt;3. FirstLevel Third Text&lt;/list-item&gt;
   &lt;list-item&gt;4. FirstLevel Fourth Text&lt;/list-item&gt;
&lt;/article&gt;

C# (tried code):

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Linq;
using System.Linq.Expressions;

namespace ListNesting1
{
    class Program
    {
        static void Main(string[] args)
        {
            XmlDocument XMLDoc1 = new XmlDocument();
            XmlNodeList NDL1;
            XmlElement XEle1;
           
            String S1, S2, StrFinal, StrEle1;
            StreamReader SR1;
            StreamWriter SW1;

            try
            {
                SR1 = new StreamReader(args[0]);
                S1 = SR1.ReadToEnd();
                SR1.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return;
            }

            XMLDoc1.LoadXml(S1);

            NDL1 = XMLDoc1.SelectNodes(&quot;//list-item&quot;);

            for(int i=0; i&lt;NDL1.Count; i++)
            {
                if (Regex.IsMatch(NDL1[i].InnerText, @&quot;^[0-9]\. &quot;))
                    {
                    StrEle1 = &quot;List1&quot;;
                }
                
                else if (Regex.IsMatch(NDL1[i].InnerText, @&quot;^[0-9]\.[0-9] &quot;))
                {
                    StrEle1 = &quot;List2&quot;;
                }
                else if (Regex.IsMatch(NDL1[i].InnerText, @&quot;^[0-9]\.[0-9]\.[0-9] &quot;))
                {
                    StrEle1 = &quot;List3&quot;;
                }
                else
                {
                    StrEle1 = &quot;List4&quot;;
                }
                XEle1 = XMLDoc1.CreateElement(StrEle1);
                S2 = NDL1[i].OuterXml;
                XEle1.InnerXml = S2;
                
                NDL1[i].ParentNode.InsertAfter(XEle1, NDL1[i]);
                NDL1[i].ParentNode.RemoveChild(NDL1[i]);
            }

            StrFinal = XMLDoc1.OuterXml;
            StrFinal = StrFinal.Replace(&quot;&lt;/List1&gt;&lt;List1&gt;&quot;, &quot;&quot;);
            StrFinal = StrFinal.Replace(&quot;&lt;/List2&gt;&lt;List2&gt;&quot;, &quot;&quot;);
            StrFinal = StrFinal.Replace(&quot;&lt;/List3&gt;&lt;List3&gt;&quot;, &quot;&quot;);
            StrFinal = StrFinal.Replace(&quot;&lt;/List4&gt;&lt;List4&gt;&quot;, &quot;&quot;);

            StrFinal = StrFinal.Replace(&quot;&lt;/list-item&gt;&lt;/List1&gt;&lt;List2&gt;&quot;, &quot;&lt;List2&gt;&quot;);
            StrFinal = StrFinal.Replace(&quot;&lt;/list-item&gt;&lt;/List2&gt;&lt;List3&gt;&quot;, &quot;&lt;List3&gt;&quot;);
            StrFinal = StrFinal.Replace(&quot;&lt;/list-item&gt;&lt;/List3&gt;&lt;List4&gt;&quot;, &quot;&lt;List4&gt;&quot;);

            StrFinal = StrFinal.Replace(&quot;&lt;/List2&gt;&lt;List1&gt;&quot;, &quot;&lt;/List2&gt;&lt;/list-item&gt;&quot;);
            StrFinal = StrFinal.Replace(&quot;&lt;/List3&gt;&lt;List2&gt;&quot;, &quot;&lt;/List3&gt;&lt;/list-item&gt;&quot;);
            StrFinal = StrFinal.Replace(&quot;&lt;/List4&gt;&lt;List3&gt;&quot;, &quot;&lt;/List4&gt;&lt;/list-item&gt;&quot;);

            StrFinal = StrFinal.Replace(&quot;&gt;&lt;&quot;, &quot;&gt;\n&lt;&quot;);

            SW1 = new StreamWriter(args[1]);
            SW1.Write(StrFinal);
            SW1.Close();
        }
    }
}

Required XML:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;article&gt;
   &lt;p&gt;The Simple list sample&lt;/p&gt;
   &lt;List1&gt;
      &lt;list-item&gt;1. First&lt;/list-item&gt;
      &lt;list-item&gt;2. Second&lt;/list-item&gt;
      &lt;list-item&gt;3. Third&lt;/list-item&gt;
   &lt;/List1&gt;
   &lt;p&gt;The Nested list sample&lt;/p&gt;
   &lt;List1&gt;
      &lt;list-item&gt;1. FirstLevel First Text
         &lt;List2&gt;
            &lt;list-item&gt;1.1 SecondLevel First Text
               &lt;List3&gt;
                  &lt;list-item&gt;1.1.1 ThirdLevel First Text&lt;/list-item&gt;
                  &lt;list-item&gt;1.1.2 ThirdLevel Second Text&lt;/list-item&gt;
               &lt;/List3&gt;
            &lt;/list-item&gt;
            &lt;list-item&gt;1.2 SecondLevel Second Text&lt;/list-item&gt;
         &lt;/List2&gt;
      &lt;/list-item&gt;
      &lt;list-item&gt;2. FirstLevel Second Text
         &lt;List2&gt;
            &lt;list-item&gt;2.1 SecondLevel First Text&lt;/list-item&gt;
            &lt;list-item&gt;2.2 SecondLevel Second Text&lt;/list-item&gt;
         &lt;/List2&gt;
      &lt;/list-item&gt;
      &lt;list-item&gt;3. FirstLevel Third Text&lt;/list-item&gt;
      &lt;list-item&gt;4. FirstLevel Fourth Text&lt;/list-item&gt;
   &lt;/List1&gt;
&lt;/article&gt;

答案1

得分: 2

以下是代码的翻译部分:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;article&gt;
    &lt;p&gt;The Simple list sample&lt;/p&gt;
    &lt;list1&gt;
        &lt;list-item&gt;1. First&lt;/list-item&gt;
        &lt;list-item&gt;2. Second&lt;/list-item&gt;
        &lt;list-item&gt;3. Third&lt;/list-item&gt;
    &lt;/list1&gt;
    &lt;p&gt;The Nested list sample&lt;/p&gt;
    &lt;list1&gt;
        &lt;list-item&gt;1. FirstLevel First Text&lt;/list-item&gt;
        &lt;list2&gt;
            &lt;list-item&gt;1.1 SecondLevel First Text&lt;/list-item&gt;
            &lt;list3&gt;
                &lt;list-item&gt;1.1.1 ThirdLevel First Text&lt;/list-item&gt;
                &lt;list-item&gt;1.1.2 ThirdLevel Second Text&lt;/list-item&gt;
            &lt;/list3&gt;
            &lt;list-item&gt;1.2 SecondLevel Second Text&lt;/list-item&gt;
        &lt;/list2&gt;
        &lt;list-item&gt;2. FirstLevel Second Text&lt;/list-item&gt;
        &lt;list2&gt;
            &lt;list-item&gt;2.1 SecondLevel First Text&lt;/list-item&gt;
            &lt;list-item&gt;2.2 SecondLevel Second Text&lt;/list-item&gt;
        &lt;/list2&gt;
        &lt;list-item&gt;3. FirstLevel Third Text&lt;/list-item&gt;
        &lt;list-item&gt;4. FirstLevel Fourth Text&lt;/list-item&gt;
    &lt;/list1&gt;
&lt;/article&gt;

希望这对你有所帮助。

英文:

C# code

using System;
using System.Text.RegularExpressions;

public class Example
{
    public static void Main()
    {
        string pattern1 = @&quot;(&lt;list-item&gt;1\. [\s\S]*?&lt;/list-item&gt;(?!\s+&lt;list-item&gt;\d))&quot;;
        string substitution1 = @&quot;&lt;list1&gt;$1&lt;/list1&gt;&quot;;

        string pattern2 = @&quot;(&lt;list-item&gt;\d\.1 [\s\S]*?&lt;/list-item&gt;(?!\s+&lt;list-item&gt;\d.\d))&quot;;
        string substitution2 = @&quot;&lt;list2&gt;$1&lt;/list2&gt;&quot;;


        string pattern3 = @&quot;(&lt;list-item&gt;\d.\d\.1 [\s\S]*?&lt;/list-item&gt;(?!\s+&lt;list-item&gt;\d.\d.\d))&quot;;
        string substitution3 = @&quot;&lt;list3&gt;$1&lt;/list3&gt;&quot;;


        string input = @&quot;&lt;?xml version=&quot;&quot;1.0&quot;&quot; encoding=&quot;&quot;UTF-8&quot;&quot;?&gt;
&lt;article&gt;
   &lt;p&gt;The Simple list sample&lt;/p&gt;
   &lt;list-item&gt;1. First&lt;/list-item&gt;
   &lt;list-item&gt;2. Second&lt;/list-item&gt;
   &lt;list-item&gt;3. Third&lt;/list-item&gt;
   &lt;p&gt;The Nested list sample&lt;/p&gt;
   &lt;list-item&gt;1. FirstLevel First Text&lt;/list-item&gt;
   &lt;list-item&gt;1.1 SecondLevel First Text&lt;/list-item&gt;
   &lt;list-item&gt;1.1.1 ThirdLevel First Text&lt;/list-item&gt;
   &lt;list-item&gt;1.1.2 ThirdLevel Second Text&lt;/list-item&gt;
   &lt;list-item&gt;1.2 SecondLevel Second Text&lt;/list-item&gt;
   &lt;list-item&gt;2. FirstLevel Second Text&lt;/list-item&gt;
   &lt;list-item&gt;2.1 SecondLevel First Text&lt;/list-item&gt;
   &lt;list-item&gt;2.2 SecondLevel Second Text&lt;/list-item&gt;
   &lt;list-item&gt;3. FirstLevel Third Text&lt;/list-item&gt;
   &lt;list-item&gt;4. FirstLevel Fourth Text&lt;/list-item&gt;
&lt;/article&gt;&quot;;

        Regex regex = new Regex(pattern1);
        input = regex.Replace(input, substitution1);


        Regex regex2 = new Regex(pattern2);
        input = regex2.Replace(input, substitution2);


        Regex regex3 = new Regex(pattern3);
        input = regex3.Replace(input, substitution3);
    }
}

output

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;article&gt;
    &lt;p&gt;The Simple list sample&lt;/p&gt;
    &lt;list1&gt;
        &lt;list-item&gt;1. First&lt;/list-item&gt;
        &lt;list-item&gt;2. Second&lt;/list-item&gt;
        &lt;list-item&gt;3. Third&lt;/list-item&gt;
    &lt;/list1&gt;
    &lt;p&gt;The Nested list sample&lt;/p&gt;
    &lt;list1&gt;
        &lt;list-item&gt;1. FirstLevel First Text&lt;/list-item&gt;
        &lt;list2&gt;
            &lt;list-item&gt;1.1 SecondLevel First Text&lt;/list-item&gt;
            &lt;list3&gt;
                &lt;list-item&gt;1.1.1 ThirdLevel First Text&lt;/list-item&gt;
                &lt;list-item&gt;1.1.2 ThirdLevel Second Text&lt;/list-item&gt;
            &lt;/list3&gt;
            &lt;list-item&gt;1.2 SecondLevel Second Text&lt;/list-item&gt;
        &lt;/list2&gt;
        &lt;list-item&gt;2. FirstLevel Second Text&lt;/list-item&gt;
        &lt;list2&gt;
            &lt;list-item&gt;2.1 SecondLevel First Text&lt;/list-item&gt;
            &lt;list-item&gt;2.2 SecondLevel Second Text&lt;/list-item&gt;
        &lt;/list2&gt;
        &lt;list-item&gt;3. FirstLevel Third Text&lt;/list-item&gt;
        &lt;list-item&gt;4. FirstLevel Fourth Text&lt;/list-item&gt;
    &lt;/list1&gt;
&lt;/article&gt;

答案2

得分: 1

这是一个用XSLT处理的任务,例如XSLT 3。在.NET框架中,Saxon HE(最新版本为Saxon HE 10.8)可作为开源包提供,可以在NuGet上找到 https://www.nuget.org/packages/Saxon-HE,也可以在 https://github.com/Saxonica/Saxon-HE/tree/main/10/Dotnet 上下载可执行文件以运行XSLT 3。

在.NET Core 6/7上,Saxonica目前只提供其商业版SaxonCS企业版本(https://www.nuget.org/packages/SaxonCS),但我已经成功使用IKVM将Saxon HE 10.8和Saxon HE 11交叉编译到.NET Core,因此您可以选择在那里运行XSLT 3.0而无需购买商业许可证:

英文:

This is a task for XSLT e.g. XSLT 3 with

&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;
xmlns:mf=&quot;http://example.com/mf&quot;
exclude-result-prefixes=&quot;#all&quot;
version=&quot;3.0&quot;&gt;
&lt;xsl:function name=&quot;mf:group&quot; as=&quot;node()*&quot;&gt;
&lt;xsl:param name=&quot;items&quot; as=&quot;map(*)*&quot;/&gt;
&lt;xsl:param name=&quot;level&quot; as=&quot;xs:integer&quot;/&gt;
&lt;xsl:choose&gt;
&lt;xsl:when test=&quot;exists($items[count(?levels) ge $level])&quot;&gt;
&lt;xsl:element name=&quot;List{$level}&quot;&gt;
&lt;xsl:for-each-group select=&quot;$items&quot; group-starting-with=&quot;.[count(?levels) eq $level]&quot;&gt;
&lt;xsl:copy select=&quot;?item&quot;&gt;
&lt;xsl:apply-templates select=&quot;node()&quot;/&gt;
&lt;xsl:sequence select=&quot;mf:group(tail(current-group()), $level + 1)&quot;/&gt;
&lt;/xsl:copy&gt;
&lt;/xsl:for-each-group&gt;
&lt;/xsl:element&gt;        
&lt;/xsl:when&gt;
&lt;xsl:otherwise&gt;
&lt;xsl:apply-templates select=&quot;$items?item&quot;/&gt;
&lt;/xsl:otherwise&gt;
&lt;/xsl:choose&gt;
&lt;/xsl:function&gt;
&lt;xsl:mode on-no-match=&quot;shallow-copy&quot;/&gt;
&lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot;/&gt;
&lt;xsl:template match=&quot;article&quot;&gt;
&lt;xsl:copy&gt;
&lt;xsl:for-each-group select=&quot;*&quot; group-adjacent=&quot;boolean(self::list-item)&quot;&gt;
&lt;xsl:choose&gt;
&lt;xsl:when test=&quot;current-grouping-key()&quot;&gt;
&lt;xsl:sequence select=&quot;mf:group(current-group()!map { &#39;item&#39; : ., &#39;levels&#39; : (. =&gt; substring-before(&#39; &#39;) =&gt; tokenize(&#39;\.&#39;))[normalize-space()]}, 1)&quot;/&gt;
&lt;/xsl:when&gt;
&lt;xsl:otherwise&gt;
&lt;xsl:apply-templates select=&quot;current-group()&quot;/&gt;
&lt;/xsl:otherwise&gt;
&lt;/xsl:choose&gt;
&lt;/xsl:for-each-group&gt;
&lt;/xsl:copy&gt;
&lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;

For the .NET framework Saxon HE (latest version for .NET framework is Saxon HE 10.8) is available as an open-source package https://www.nuget.org/packages/Saxon-HE on NuGet as well as an executable download https://github.com/Saxonica/Saxon-HE/tree/main/10/Dotnet to run XSLT 3.

On .NET Core 6/7 Saxonica currently only has its commercial SaxonCS enterprise version (https://www.nuget.org/packages/SaxonCS) available but I have managed to cross compile both Saxon HE 10.8 as well as Saxon HE 11 using IKVM to .NET Core so even there you have the option to run XSLT 3.0 without needing to buy a commercial license:

答案3

得分: 1

这是一些你可能想尝试的内容。 它与你要求的输出不完全匹配(&lt;Listx&gt; 元素不在先前的 &lt;list-item&gt; 中,但非常接近。

using System.Xml.Linq;
var xml = XmlString();
var s = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml));
var x = XElement.Load(s);
XElement rootArticle = new XElement("article");
XElement parentElement = rootArticle;
List<int> currentLevel = new List<int>();
foreach (var currentElement in x.Descendants())
{
// 当不是 list-item 时,展开
if (currentElement.Name != "list-item")
{
while (currentLevel.Count > 0)
{
parentElement = parentElement.Parent;
currentLevel.RemoveAt(currentLevel.Count - 1);
}
parentElement.Add(currentElement);
continue;
}
var headertext = (currentElement.FirstNode as XText)?.Value ?? string.Empty;
List<int> previousLevel = currentLevel;
currentLevel = headertext[..(headertext + " ").IndexOf(' ')].TrimEnd('.').Split('.').Select(x => { var _ = int.TryParse(x, out var n); return n; }).ToList();
// 如果当前级别在同一序列中
if (currentLevel.Count > 0 && currentLevel.Count >= previousLevel.Count && Enumerable.Range(0, previousLevel.Count).All(i => currentLevel[i] >= previousLevel[i]))
{
// 添加所需的列表以匹配标题深度
for (int i = 0; i < currentLevel.Count - previousLevel.Count; i++)
{
XElement listElement = new XElement("List" + (i + previousLevel.Count + 1));
parentElement.Add(listElement);
parentElement = listElement;
}
parentElement.Add(currentElement);
continue;
}
// 返回到具有匹配深度的父元素
var depth = previousLevel.Take(currentLevel.Count).Where((n, i) => n <= currentLevel[i]).Count();
for (int i = depth; i < previousLevel.Count; i++)
{
parentElement = parentElement.Parent;
}
// 添加所需的列表以匹配标题深度
for (int i = depth; i < currentLevel.Count; i++)
{
XElement listElement = new XElement("List" + (i + 1));
parentElement.Add(listElement);
parentElement = listElement;
}
parentElement.Add(currentElement);
}
Console.WriteLine(rootArticle.ToString());
// <article>
//   <p>The Simple list sample</p>
//   <List1>
//     <list-item>1. First</list-item>
//     <list-item>2. Second</list-item>
//     <list-item>3. Third</list-item>
//   </List1>
//   <p>The Nested list sample</p>
//   <List1>
//     <list-item>1. FirstLevel First Text</list-item>
//     <List2>
//       <list-item>1.1 SecondLevel First Text</list-item>
//       <List3>
//         <list-item>1.1.1 ThirdLevel First Text</list-item>
//         <list-item>1.1.2 ThirdLevel Second Text</list-item>
//       </List3>
//       <list-item>1.2 SecondLevel Second Text</list-item>
//     </List2>
//     <list-item>2. FirstLevel Second Text</list-item>
//     <List2>
//       <list-item>2.1 SecondLevel First Text</list-item>
//       <list-item>2.2 SecondLevel Second Text</list-item>
//     </List2>
//     <list-item>3. FirstLevel Third Text</list-item>
//     <list-item>4. FirstLevel Fourth Text</list-item>
//   </List1>
// </article>
static string XmlString() => @"<?xml version=""1.0"" encoding=""UTF-8""?>
<article>
<p>The Simple list sample</p>
<list-item>1. First</list-item>
<list-item>2. Second</list-item>
<list-item>3. Third</list-item>
<p>The Nested list sample</p>
<list-item>1. FirstLevel First Text</list-item>
<list-item>1.1 SecondLevel First Text</list-item>
<list-item>1.1.1 ThirdLevel First Text</list-item>
<list-item>1.1.2 ThirdLevel Second Text</list-item>
<list-item>1.2 SecondLevel Second Text</list-item>
<list-item>2. FirstLevel Second Text</list-item>
<list-item>2.1 SecondLevel First Text</list-item>
<list-item>2.2 SecondLevel Second Text</list-item>
<list-item>3. FirstLevel Third Text</list-item>
<list-item>4. FirstLevel Fourth Text</list-item>
</article>";
英文:

Here's something you might want to play with.
It doesn't match your required output (the &lt;Listx&gt; elements are not inside the previous &lt;list-item&gt; but it's pretty close.

using System.Xml.Linq;
var xml = XmlString();
var s = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml));
var x = XElement.Load(s);
XElement rootArticle = new (&quot;article&quot;);
XElement parentElement = rootArticle;
List&lt;int&gt; currentLevel = new ();
foreach (var currentElement in x.Descendants())
{
// When not a list-item, unwind
if (currentElement.Name != &quot;list-item&quot;)
{
while (currentLevel.Count &gt; 0)
{
parentElement = parentElement.Parent;
currentLevel.RemoveAt(currentLevel.Count - 1);
}
parentElement!.Add(currentElement);
continue;
}
var headertext = (currentElement.FirstNode as XText)?.Value ?? string.Empty;
List&lt;int&gt; previousLevel = currentLevel;
currentLevel = headertext[..(headertext + &quot; &quot;).IndexOf(&#39; &#39;)].TrimEnd(&#39;.&#39;).Split(&#39;.&#39;).Select(x =&gt; { var _ = int.TryParse(x, out var n); return n; }).ToList();
// If current level is in same sequence
if (currentLevel.Count &gt; 0 &amp;&amp; currentLevel.Count &gt;= previousLevel.Count &amp;&amp; Enumerable.Range(0, previousLevel.Count).All(i =&gt; currentLevel[i] &gt;= previousLevel[i]))
{
// Add required lists to match header depth
for (int i = 0; i &lt; currentLevel.Count - previousLevel.Count; i++)
{
XElement listElement = new ($&quot;List{i + previousLevel.Count + 1}&quot;);
parentElement.Add(listElement);
parentElement = listElement;
}
parentElement.Add(currentElement);
continue;
}
// Go back to parent with matching depth
var depth = previousLevel.Take(currentLevel.Count).Where((n, i) =&gt; n &lt;= currentLevel[i]).Count();
for (int i=depth; i &lt; previousLevel.Count; i++)
{
parentElement = parentElement!.Parent;
}
// Add required lists to match header depth
for (int i = depth; i &lt; currentLevel.Count; i++)
{
XElement listElement = new ($&quot;List{i + 1}&quot;);
parentElement!.Add(listElement);
parentElement = listElement;
}
parentElement!.Add(currentElement);
}
Console.WriteLine(rootArticle.ToString());
// &lt;article&gt;
//   &lt;p&gt;The Simple list sample&lt;/p&gt;
//   &lt;List1&gt;
//     &lt;list-item&gt;1. First&lt;/list-item&gt;
//     &lt;list-item&gt;2. Second&lt;/list-item&gt;
//     &lt;list-item&gt;3. Third&lt;/list-item&gt;
//   &lt;/List1&gt;
//   &lt;p&gt;The Nested list sample&lt;/p&gt;
//   &lt;List1&gt;
//     &lt;list-item&gt;1. FirstLevel First Text&lt;/list-item&gt;
//     &lt;List2&gt;
//       &lt;list-item&gt;1.1 SecondLevel First Text&lt;/list-item&gt;
//       &lt;List3&gt;
//         &lt;list-item&gt;1.1.1 ThirdLevel First Text&lt;/list-item&gt;
//         &lt;list-item&gt;1.1.2 ThirdLevel Second Text&lt;/list-item&gt;
//       &lt;/List3&gt;
//       &lt;list-item&gt;1.2 SecondLevel Second Text&lt;/list-item&gt;
//     &lt;/List2&gt;
//     &lt;list-item&gt;2. FirstLevel Second Text&lt;/list-item&gt;
//     &lt;List2&gt;
//       &lt;list-item&gt;2.1 SecondLevel First Text&lt;/list-item&gt;
//       &lt;list-item&gt;2.2 SecondLevel Second Text&lt;/list-item&gt;
//     &lt;/List2&gt;
//     &lt;list-item&gt;3. FirstLevel Third Text&lt;/list-item&gt;
//     &lt;list-item&gt;4. FirstLevel Fourth Text&lt;/list-item&gt;
//   &lt;/List1&gt;
// &lt;/article&gt;
static string XmlString() =&gt; @&quot;&lt;?xml version=&quot;&quot;1.0&quot;&quot; encoding=&quot;&quot;UTF-8&quot;&quot;?&gt;
&lt;article&gt;
&lt;p&gt;The Simple list sample&lt;/p&gt;
&lt;list-item&gt;1. First&lt;/list-item&gt;
&lt;list-item&gt;2. Second&lt;/list-item&gt;
&lt;list-item&gt;3. Third&lt;/list-item&gt;
&lt;p&gt;The Nested list sample&lt;/p&gt;
&lt;list-item&gt;1. FirstLevel First Text&lt;/list-item&gt;
&lt;list-item&gt;1.1 SecondLevel First Text&lt;/list-item&gt;
&lt;list-item&gt;1.1.1 ThirdLevel First Text&lt;/list-item&gt;
&lt;list-item&gt;1.1.2 ThirdLevel Second Text&lt;/list-item&gt;
&lt;list-item&gt;1.2 SecondLevel Second Text&lt;/list-item&gt;
&lt;list-item&gt;2. FirstLevel Second Text&lt;/list-item&gt;
&lt;list-item&gt;2.1 SecondLevel First Text&lt;/list-item&gt;
&lt;list-item&gt;2.2 SecondLevel Second Text&lt;/list-item&gt;
&lt;list-item&gt;3. FirstLevel Third Text&lt;/list-item&gt;
&lt;list-item&gt;4. FirstLevel Fourth Text&lt;/list-item&gt;
&lt;/article&gt;&quot;;

huangapple
  • 本文由 发表于 2023年2月8日 12:53:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75381504.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定