最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How to restart numbered list in table cell using openxml .net - Stack Overflow

programmeradmin1浏览0评论

I want to generate a word file based on data from the database. The data may or may not contain html tag and i handle this. so, when it detects the "ul" or "ol" tag it should be list. for "ul" tag i have no issue, but for "ol" tag, the numbers in the list continue in different cells in my table generated. Can someone help me fix this.

I checked my format after generating the file by changing the extension to .zip to view document.xml and numbering.xml.

Here in my numbering.xml, my numbered list defined like this:

<w:abstractNum w:abstractNumId="2">
  <w:lvl w:ilvl="0">
    <w:start w:val="1"/>
    <w:numFmt w:val="decimal"/>
    <w:lvlText w:val="%1."/>
    <w:numRestart w:val="eachSect"/>
    <w:pPr>
      <w:ind w:left="360" w:hanging="360"/>
    </w:pPr>
  </w:lvl>
</w:abstractNum>

and i have map the numId to the list:

<w:num w:numId="7">
  <w:abstractNumId w:val="2"/>
</w:num>

<w:num w:numId="8">
  <w:abstractNumId w:val="2"/>
</w:num>

for my document.xml:

in cell 1:

<w:p>
  <w:pPr>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="7"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>SOME TEXT</w:t>
  </w:r>
</w:p>

in Cell 2 same table:

<w:p>
  <w:pPr>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="8"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>SOME TEXT</w:t>
  </w:r>
</w:p>

Code: Method to define number list:

private void DefineNumberingStyles(MainDocumentPart mainPart)
    {
        NumberingDefinitionsPart numberingPart = mainPart.NumberingDefinitionsPart ?? mainPart.AddNewPart<NumberingDefinitionsPart>();

        if (numberingPart.Numbering == null)
        {
            numberingPart.Numbering = new Numbering();
        }

        Numbering numbering = numberingPart.Numbering;

        // Define Bullet List
        AbstractNum bulletAbstractNum = new AbstractNum(
            new Level(
                new NumberingFormat() { Val = NumberFormatValues.Bullet },
                new LevelText() { Val = "•" }, // Bullet symbol
                new ParagraphProperties(
                    new Indentation() { Left = "360", Hanging = "360" }
                )
            ) { LevelIndex = 0 }
        ) { AbstractNumberId = 1 };

        // Define Numbered List
        AbstractNum numberedAbstractNum = new AbstractNum(
            new Level(
                new StartNumberingValue() { Val = 1 },
                new NumberingFormat() { Val = NumberFormatValues.Decimal },
                new LevelText() { Val = "%1." }, // Number format
                new NumberingRestart() { Val = RestartNumberValues.EachSection },
                new ParagraphProperties(
                    new Indentation() { Left = "360", Hanging = "360" }
                )
            ) { LevelIndex = 0 }
        ) { AbstractNumberId = 2 };


        // Assign IDs
        numbering.Append(bulletAbstractNum, numberedAbstractNum);

        numbering.Append(new NumberingInstance(new AbstractNumId() { Val = 1 }) { NumberID = 1 }); // Bullets
        numbering.Append(new NumberingInstance(new AbstractNumId() { Val = 2 }) { NumberID = 2 }); // Numbers
    }

Logic to append data into cell:

else if (node.Name == "ul" || node.Name == "ol")
        {
            bool isOrdered = node.Name == "ol";
            //int numberingId = isOrdered ? CheckNumberListStyle(node) : CheckBulletListStyle(node); // 1 = Bullets, 2 = Numbers.
            NumberingDefinitionsPart numberingPart = mainPart.NumberingDefinitionsPart ?? mainPart.AddNewPart<NumberingDefinitionsPart>();
            if (numberingPart.Numbering == null)
            {
                numberingPart.Numbering = new Numbering();
            }
            Numbering numbering = numberingPart.Numbering;

            if (isOrdered)
            {
                // Create new numbering instance
                NumberingInstance numberingInstance = new NumberingInstance(
                    new AbstractNumId() { Val = 2 }
                ) { NumberID = uniqueId };
                numbering.Append(numberingInstance);
            } else 
            {
                // Create new numbering instance
                NumberingInstance numberingInstance = new NumberingInstance(
                    new AbstractNumId() { Val = 1 }
                ) { NumberID = uniqueId };
                numbering.Append(numberingInstance);
            }

            var listItems = node.SelectNodes("li");
            if (listItems != null)
            {
                foreach (HtmlNode li in listItems)
                {
                    // ** Remove unnecessary bullets inside <li> **
                    HtmlNode bulletNode = li.SelectSingleNode(".//span[contains(@style, 'mso-list')]"); // Find bullet span
                    if (bulletNode != null)
                    {
                        bulletNode.Remove(); // Remove bullet from text extraction
                    }

                    string childText = HttpUtility.HtmlDecode(li.InnerText.Trim());

                    Paragraph para = new Paragraph(
                        new ParagraphProperties(
                            new NumberingProperties(
                                new NumberingLevelReference() { Val = 0 },
                                new NumberingId() { Val = uniqueId }
                            )
                        )
                    );

                    Run run = new Run();
                    run.AppendChild(new Text(childText));

                    para.AppendChild(run);
                    parentElement.AppendChild(para);
                }
            }
        }

I want to generate a word file based on data from the database. The data may or may not contain html tag and i handle this. so, when it detects the "ul" or "ol" tag it should be list. for "ul" tag i have no issue, but for "ol" tag, the numbers in the list continue in different cells in my table generated. Can someone help me fix this.

I checked my format after generating the file by changing the extension to .zip to view document.xml and numbering.xml.

Here in my numbering.xml, my numbered list defined like this:

<w:abstractNum w:abstractNumId="2">
  <w:lvl w:ilvl="0">
    <w:start w:val="1"/>
    <w:numFmt w:val="decimal"/>
    <w:lvlText w:val="%1."/>
    <w:numRestart w:val="eachSect"/>
    <w:pPr>
      <w:ind w:left="360" w:hanging="360"/>
    </w:pPr>
  </w:lvl>
</w:abstractNum>

and i have map the numId to the list:

<w:num w:numId="7">
  <w:abstractNumId w:val="2"/>
</w:num>

<w:num w:numId="8">
  <w:abstractNumId w:val="2"/>
</w:num>

for my document.xml:

in cell 1:

<w:p>
  <w:pPr>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="7"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>SOME TEXT</w:t>
  </w:r>
</w:p>

in Cell 2 same table:

<w:p>
  <w:pPr>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="8"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>SOME TEXT</w:t>
  </w:r>
</w:p>

Code: Method to define number list:

private void DefineNumberingStyles(MainDocumentPart mainPart)
    {
        NumberingDefinitionsPart numberingPart = mainPart.NumberingDefinitionsPart ?? mainPart.AddNewPart<NumberingDefinitionsPart>();

        if (numberingPart.Numbering == null)
        {
            numberingPart.Numbering = new Numbering();
        }

        Numbering numbering = numberingPart.Numbering;

        // Define Bullet List
        AbstractNum bulletAbstractNum = new AbstractNum(
            new Level(
                new NumberingFormat() { Val = NumberFormatValues.Bullet },
                new LevelText() { Val = "•" }, // Bullet symbol
                new ParagraphProperties(
                    new Indentation() { Left = "360", Hanging = "360" }
                )
            ) { LevelIndex = 0 }
        ) { AbstractNumberId = 1 };

        // Define Numbered List
        AbstractNum numberedAbstractNum = new AbstractNum(
            new Level(
                new StartNumberingValue() { Val = 1 },
                new NumberingFormat() { Val = NumberFormatValues.Decimal },
                new LevelText() { Val = "%1." }, // Number format
                new NumberingRestart() { Val = RestartNumberValues.EachSection },
                new ParagraphProperties(
                    new Indentation() { Left = "360", Hanging = "360" }
                )
            ) { LevelIndex = 0 }
        ) { AbstractNumberId = 2 };


        // Assign IDs
        numbering.Append(bulletAbstractNum, numberedAbstractNum);

        numbering.Append(new NumberingInstance(new AbstractNumId() { Val = 1 }) { NumberID = 1 }); // Bullets
        numbering.Append(new NumberingInstance(new AbstractNumId() { Val = 2 }) { NumberID = 2 }); // Numbers
    }

Logic to append data into cell:

else if (node.Name == "ul" || node.Name == "ol")
        {
            bool isOrdered = node.Name == "ol";
            //int numberingId = isOrdered ? CheckNumberListStyle(node) : CheckBulletListStyle(node); // 1 = Bullets, 2 = Numbers.
            NumberingDefinitionsPart numberingPart = mainPart.NumberingDefinitionsPart ?? mainPart.AddNewPart<NumberingDefinitionsPart>();
            if (numberingPart.Numbering == null)
            {
                numberingPart.Numbering = new Numbering();
            }
            Numbering numbering = numberingPart.Numbering;

            if (isOrdered)
            {
                // Create new numbering instance
                NumberingInstance numberingInstance = new NumberingInstance(
                    new AbstractNumId() { Val = 2 }
                ) { NumberID = uniqueId };
                numbering.Append(numberingInstance);
            } else 
            {
                // Create new numbering instance
                NumberingInstance numberingInstance = new NumberingInstance(
                    new AbstractNumId() { Val = 1 }
                ) { NumberID = uniqueId };
                numbering.Append(numberingInstance);
            }

            var listItems = node.SelectNodes("li");
            if (listItems != null)
            {
                foreach (HtmlNode li in listItems)
                {
                    // ** Remove unnecessary bullets inside <li> **
                    HtmlNode bulletNode = li.SelectSingleNode(".//span[contains(@style, 'mso-list')]"); // Find bullet span
                    if (bulletNode != null)
                    {
                        bulletNode.Remove(); // Remove bullet from text extraction
                    }

                    string childText = HttpUtility.HtmlDecode(li.InnerText.Trim());

                    Paragraph para = new Paragraph(
                        new ParagraphProperties(
                            new NumberingProperties(
                                new NumberingLevelReference() { Val = 0 },
                                new NumberingId() { Val = uniqueId }
                            )
                        )
                    );

                    Run run = new Run();
                    run.AppendChild(new Text(childText));

                    para.AppendChild(run);
                    parentElement.AppendChild(para);
                }
            }
        }
Share asked Mar 4 at 8:49 UnknownUnknown 741 silver badge4 bronze badges 1
  • The following may be of interest: Tutorial: Learn to debug C# code using Visual Studio – It all makes cents Commented Mar 4 at 16:12
Add a comment  | 

1 Answer 1

Reset to default 1

I solved the issue by using the StartOverrideNumberingValue class every time I create a new numbering instance. This class explicitly forces a restart when the numId changes.

Even though I used the NumberingRestart class when defining my list, Word still did not recognize whether the list should restart, even if the numId was different and the abstractId was correctly mapped to it. So StartOverrideNumberingValue is required to explicitly tell word to restart the numbering when the numId is changes.

Example how i do it:

// Create a new NumberingInstance
var numberingInstance = new NumberingInstance(new AbstractNumId() { Val = abstractNumId })
{
    NumberID = uniqueId
};

// Append the StartOverrideNumberingValue to the numbering instance
numberingInstance.Append(new StartOverrideNumberingValue() { Val = 1 });
发布评论

评论列表(0)

  1. 暂无评论