none
WorprocessingML - Problem with w:num elements (numbered lists are broken at a limit of 2020) RRS feed

  • Question

  • Hi, I've got a question concerning WordprocessingML!

    I'm generating some word file with many numbered lists. It works fine for the first 2020 lists. But all further lists are broken (word displays no more numbering). The generated XML looks okay for the broken lists (just like the working lists before).

    Is there a limit of possible <w:num> elements?

    Hope someone could help me?

    Many thanks in advance!
    Wednesday, January 22, 2014 12:17 PM

All replies

  • Hi tom_dy,

    I've checked the MSDN document, there seems no declaration about the limit of numbered lists.

    Could you please post your code which generates those numbered lists? Maybe I can have a test with it.

    Thanks.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, January 23, 2014 11:51 AM
    Moderator
  • Hi, thank you for your fast answer

    here is the part of the code that generates a list paragraph. There are several checks e.g. check if list restarts, use existing numId if it is a bulleted list that already uses the given listStyleId ....

    Hope the code snippet helps:

            private static int numId = -1;
            private static int abstractNumId = -1;

            public static Paragraph CreateListParagraph(ParagraphData paraData, int level, Boolean restart, String listStyleId, MainDocumentPart mainPart)
            {
                Document doc = mainPart.Document;
                NumberingDefinitionsPart numPart = mainPart.NumberingDefinitionsPart;
                String templateCode = GetTemplateValueForStyle(numPart.Numbering, listStyleId);

                if (restart)
                {
                    Int32Value abstractNumIdTemp = null;
                    Int32Value numberingIdTemp = null;
                    // search for numberingId and abstarctNumberingId using listStyle
                    if (IsBulletNumberingFormat(listStyleId, mainPart))
                    {
                        foreach (NumberingStyleLink numStyleLink in numPart.Numbering.Descendants<NumberingStyleLink>().ToList())
                        {
                            if (numStyleLink.Val.Value.Equals(listStyleId))
                            {
                                AbstractNum abstractNum = (AbstractNum)numStyleLink.Parent;
                                abstractNumIdTemp = abstractNum.AbstractNumberId;
                                foreach (NumberingInstance numberingInstance in numPart.Numbering.Descendants<NumberingInstance>().ToList())
                                {
                                    AbstractNumId temp = numberingInstance.Descendants<AbstractNumId>().First();//.Val;
                                    if (abstractNumIdTemp == (temp.Val.Value))
                                    {
                                        numberingIdTemp = numberingInstance.NumberID;
                                        break;
                                    }
                                }
                                break;
                            }
                        }
                    }
                    if (abstractNumIdTemp == null || numberingIdTemp == null)
                    {
                        // create new abstract numbering
                        int maxAbstractNumberingId = -1;
                        foreach (AbstractNum abstractNum in numPart.Numbering.Descendants<AbstractNum>())
                        {
                            String currentAbstractNumId = abstractNum.AbstractNumberId;
                            if (Convert.ToInt32(currentAbstractNumId) > maxAbstractNumberingId)
                                maxAbstractNumberingId = Convert.ToInt32(currentAbstractNumId);
                        }
                        abstractNumId = maxAbstractNumberingId + 1;
                        AbstractNum newAbstractNum = new AbstractNum() { NumberingStyleLink = new NumberingStyleLink() { Val = listStyleId }, AbstractNumberId = Convert.ToInt32(abstractNumId), TemplateCode = new TemplateCode() { Val = templateCode }, MultiLevelType = new MultiLevelType() { Val = MultiLevelValues.Multilevel } };
                        numPart.Numbering.InsertAfter<AbstractNum>(newAbstractNum, numPart.Numbering.Descendants<AbstractNum>().Last());

                        // create new numbering instance
                        int maxNumberingId = -1;
                        foreach (NumberingInstance num in numPart.Numbering.Descendants<NumberingInstance>())
                        {
                            int currentNumId = num.NumberID.Value;
                            if (currentNumId > maxNumberingId)
                                maxNumberingId = currentNumId;
                        }
                        numId = maxNumberingId + 1;
                        NumberingInstance numInstance = new NumberingInstance() { NumberID = numId, AbstractNumId = new AbstractNumId() { Val = Convert.ToInt32(abstractNumId) } };
                        numPart.Numbering.Append(numInstance);
                    }
                    else
                    {
                        numId = numberingIdTemp;
                    }
                }

                Paragraph paragraph = new Paragraph();
                SpacingBetweenLines spacing = new SpacingBetweenLines() { After = "0", Before = "0", AfterLines = 0, BeforeLines = 0 };
                ParagraphProperties paraProperties = new ParagraphProperties() { SpacingBetweenLines = spacing };

                NumberingProperties numProperties = new NumberingProperties();
                NumberingLevelReference ilvl = new NumberingLevelReference() { Val = level };
                NumberingId newNumId = new NumberingId() { Val = numId };
                numProperties.Append(ilvl);
                numProperties.Append(newNumId);
                paraProperties.Append(numProperties);
                paragraph.Append(paraProperties);


                foreach (Object run in paraData.Runs)
                {
                    if (run.GetType() == typeof(String))
                    {
                        CreateRunElement(paragraph, new TextRun((String)run), mainPart);
                    }
                    else if (run.GetType() == typeof(TextRun))
                    {
                        CreateRunElement(paragraph, (TextRun)run, mainPart);
                    }
                    else if (run.GetType() == typeof(ImageData))
                    {
                        paragraph.Append(CreateImageRunElement((ImageData)run, mainPart));
                    }
                    else if (run.GetType() == typeof(Tabulator))
                    {
                        paragraph.Append(new Run(new TabChar()));
                    }
                    else if (run.GetType() == typeof(Break))
                    {
                        paragraph.Append(new Run(new Break()));
                    }
                }

                return paragraph;
            }

            public static String GetTemplateValueForStyle(Numbering numbering, String styleId)
            {
                foreach (AbstractNum abstractNum in numbering.Descendants<AbstractNum>())
                {
                    if (abstractNum.StyleLink != null && abstractNum.Descendants<Level>() != null)
                    {
                        String styleVal = abstractNum.StyleLink.Val;
                        if (styleVal.Equals(styleId))
                            return abstractNum.TemplateCode.Val;
                    }
                }
                return null;
            }

            public static bool IsBulletNumberingFormat(String listStyleId, MainDocumentPart mainPart)
            {
                NumberingDefinitionsPart numPart = mainPart.NumberingDefinitionsPart;
                // check if numbering is "bullet" or other
                foreach (OpenXmlElement elem in mainPart.StyleDefinitionsPart.Styles)
                {
                    if (elem.GetType() == typeof(Style))
                    {
                        Style style = (Style)elem;
                        if (style.StyleId.Value.Equals(listStyleId))
                        {
                            Int32Value numId = style.Descendants<NumberingId>().First().Val;
                            int absNumId = -1;
                            foreach (NumberingInstance numInstance in numPart.Numbering.Descendants<NumberingInstance>().ToList())
                            {
                                if (numInstance.NumberID.Value == numId)
                                {
                                    absNumId = numInstance.AbstractNumId.Val.Value;
                                }
                            }
                            if (absNumId != -1)
                            {
                                foreach (AbstractNum abstractNum in numPart.Numbering.Descendants<AbstractNum>().ToList())
                                {
                                    if (abstractNum.AbstractNumberId.Value == absNumId)
                                    {
                                        if (abstractNum.Descendants<Level>().First().NumberingFormat.Val.Value.Equals(NumberFormatValues.Bullet))
                                            return true;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                    }
                }
                return false;
            }

    The generated num-elements and abstractNum-elements look okay and do not differ from the working ones (only the numId and the value of abstractNumId are different of course). I check that with the Open XML SDK Productivity Tool...

    <w:num w:numId="687" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:abstractNumId w:val="1165" />
    </w:num>

    <w:abstractNum w:abstractNumId="1165" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:nsid w:val="4A3E0246" />
      <w:multiLevelType w:val="multilevel" />
      <w:tmpl w:val="E21495CA" />
      <w:numStyleLink w:val="Numbered" />
    </w:abstractNum> 

    Thursday, January 23, 2014 1:09 PM
  • Hi tom

    Although no limit may be mentioned in the documentation there has always been a "practical" limit in Word.

    I'm not really familiar with this part of the Open XML SDK object model, so I can't tell by skimming your code... Are you creating 2020+ individual list templates (numbering definitions)? Or applying a few list templates 2020+ times?

    If the former, you should try re-using a few list templates and not generate a new one for each block of numbering. (Microsoft even needed to incorporate a list template-removal into Word to keep the number at a level that won't "break" documents - that's how critical this is.)


    Cindy Meister, VSTO/Word MVP, my blog

    Thursday, January 23, 2014 7:59 PM
    Moderator
  • Hi,

    thanks for your fast feedback again!

    In my case I have to generate a new <w:num> element for a new list because it is needed to restart the numbering of the new list at "1". (With bulleted lists that doesn't matter... I can always use the same <w:num> and <w:abstractNum> element. I don't have to restart numbering...)

    I can always refere to the same <w:abstractNum> element (for numbered lists) instead of generating for each <w:num> an own <w:abstractNum>. That is right, thanks. But the problem still exists! At a numId of 2047 the lists are broken.

    Just like this:

    <!-- my first numbered list that uses <w:abstractNum> with id=34 -->

    <w:num w:numId="35" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:abstractNumId w:val="34" />
    </w:num>

    <!-- my second numbered list that also uses <w:abstractNum> with id=34 and restarts numbering at 1 on level 1 and 2-->

    <w:num w:numId="36" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:abstractNumId w:val="34" />
      <w:lvlOverride w:ilvl="0">
        <w:startOverride w:val="1" />
      </w:lvlOverride>
      <w:lvlOverride w:ilvl="1">
        <w:startOverride w:val="1" />
      </w:lvlOverride>
    </w:num>

    <!-- my third numbered list that also uses <w:abstractNum> with id=34 and also restarts numbering at 1 on level 1 and 2-->

    <w:num w:numId="37" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:abstractNumId w:val="34" />
      <w:lvlOverride w:ilvl="0">
        <w:startOverride w:val="1" />
      </w:lvlOverride>
      <w:lvlOverride w:ilvl="1">
        <w:startOverride w:val="1" />
      </w:lvlOverride>
    </w:num>

    I guess the problem is the 32-bit version of Microsoft Word: when opening the generated document Word displays a warning: There is not enough memory or disk space to update the display.

    If I open the generated Document e.g. with LibreOffice (64-bit) then the lists are all okay! Unfortunately I have no 64-bit Word version in order to verify my suspicion :(

    Many thanks for any ideas in advance!


    • Edited by tom_dy Monday, January 27, 2014 5:51 PM typing error
    Friday, January 24, 2014 1:01 PM