This project has moved. For the latest updates, please go here.

Should H1 restart the numbering of H2 or I am doing something wrong in the template?

Feb 6, 2015 at 11:10 PM
Imported the following HTML:
<h1>This is H1</h1>
    <h2>This is H2</h2>
    <h2>Another H2</h2>
<h1>This is another H1</h1>
    <h2>This is H2</h2>
    <h2>Another H2</h2>
<h1>Last H1</h1>
    <h2>This is H2</h2>
    <h2>Another H2</h2>
And I expected to see that each H1 restarted the numbering of the H2s that followed. But this is what is imported:
A. This is H1
  1. This is H2
  2. Another H2
B. This is another H1
  3. This is H2
  4. Another H2
C. Last H1
  5. This is H2
  6. Another H2
What should I do to have the H2s restart their numbering after every H1?

Thank you!
Feb 9, 2015 at 6:43 PM
Edited Feb 9, 2015 at 7:15 PM
While awaiting your guidance, I developed the following workaround code, which is working for the most part, but there is still an issue.
List<Tuple<String, Int32>> lHeadings = new List<Tuple<String, Int32>>(); // to store the Heading#s inserted

foreach (Paragraph p in converter.Parse(s))
{
    String v = (((DocumentFormat.OpenXml.Wordprocessing.StringType)(((p).ParagraphProperties).ParagraphStyleId))).Val.Value;

    if (v.Contains("Heading"))
    {
        Int32 level = Int32.Parse(Regex.Match(v, @"-?\d+").Value); // Find out level of the currently inserted Heading

        // If the headings list is empty, initialize with 1 for the first kind of heading being added
        if (lHeadings.Count == 0)
        {
            numId = 1; // Int32 class member to store Numbering ID
            lHeadings.Add(new Tuple<String, Int32>(v, numId));
        }

        var t = lHeadings.Last();

        // Level is deeper than the last stored level (ex: now Heading2, was Heding1)
        if (level > Int32.Parse(Regex.Match(t.Item1, @"-?\d+").Value)) 
        {
            Tuple<String, Int32> tcur = null;

            foreach (var tpl in lHeadings)
            {
                if (tpl.Item1.Equals(v))
                {
                    tcur = tpl;
                    break;
                }
            }

            numId = GetMaxNumberingId(lHeadings) + 1; // Start a brand new numbering

            // The heading level being added already exists - remove it to replace with incremented numbering ID
            if (tcur != null)
            {
                lHeadings.Remove(tcur);
            }

            lHeadings.Add(new Tuple<String, Int32>(v, numId));
        }

        // When heading being added is higher than current (ex. Heading1 after Heading3)
        if (level < Int32.Parse(Regex.Match(t.Item1, @"-?\d+").Value))
        {
            // Search for the heading level currently being added
            foreach (var tpl in lHeadings)
            {
                if (tpl.Item1.Equals(v))
                {
                    numId = tpl.Item2; // Continue using the found numberind ID for the heading level currently being added
                    lHeadings.Remove(tpl); // Remove the existing entry for the heading level currently being added
                    lHeadings.Add(new Tuple<String, Int32>(v, numId)); // Re-add an entry for the heading level currently being added
                    break;
                }
            }
        }

        p.ParagraphProperties.NumberingProperties = new NumberingProperties(
            new NumberingLevelReference()
            {
                Val = level - 1
            },
            new NumberingId()
            {
                Val = numId
            }
        );
    }

    body.Append(p);
}

document.MainDocumentPart.Document.Save();
This is what I see in the resulting document:
1. This is H1
  a. This is H2
  b. Another H2
2. This is another H1
  a. This is H2 again
  b. Another H2 again
    i. First H3
    ii. Second H3
  c. Closing H2 again
3. Last H1
  a. This is H2 once more
  b. Another H2 onve more
The code above takes care about re-starting numbering when a parent-level header comes after a child-level header (i.e. when H1 appears after for example H2).
But in the resulting Word document numbering of all my levels are 1 level too deep, i.e. Heading1 in the template should be ABC, but it is 2nd level - 123, etc.

The first line should be numbered "A. This is H1" as specified in the template, but somehow the numbering is off by 1 level.

Am I using a wrong approach to control heading numbering?

EDIT:

Just fixed that by replading the code which assigned NumberingProperties with the following code, but I don't understand what I am doing now, i.e. why the 1st level needs -1, but subsequent levels -2 for the level???
        if (level == 1)
        {
            p.ParagraphProperties.NumberingProperties = new NumberingProperties(
                new NumberingLevelReference() { Val = level - 1 }
            );
        }
        else
        {
            p.ParagraphProperties.NumberingProperties = new NumberingProperties(
                new NumberingLevelReference() { Val = level - 2 },
                new NumberingId() { Val = numId }
            );
        }
Feb 10, 2015 at 4:07 PM
Edited Feb 10, 2015 at 4:08 PM
Now I realize that NumberingLevelReference should have Val = 0.

But even though the code above correctly keeps <H1>s all in numbering #1 and increments numbering for all other levels as they increase or decrease, the resulting document is still a terrible mess: at first numbering seems to be correct, but then it goes completely out of whack: at first the lower headings start changing number format, then they suddenly slide back into the H1 numbering and interfere with the H1s.

The only way to keep some order seems to be not to even attempt to control the numbering this way and revert to Word's default behaviour: allowing all levels of headings to be numbered front to back continuously without attempting to start anew after the higher level headings. (I.e. it seems that Word has no concept of document sectioning).

When I am pointing at for exsample Heading2 in Word and bring up "Set Numbering Value" dialogue, it does not actually restart the numbering - it changes the style itself.

Just a theoretical question: what would be a programmatic equivalent of using "Set Numbering Value" dialogue to to "Start a new list" at 1?
Coordinator
Feb 10, 2015 at 9:08 PM
Just a simple question, are you trying to achieve a table of contents?
Because there is easier way :-)

If you want to use your own list instance style, I recommend you to define it by Word, then append the conversion into your document.
If you still want to perform it by code, take a look at NumberingListStyleCollection.cs (function InitNumberingIds) and copy this snippet to your program.
Update with your wished configuration (level 1 = LowerLetter for example).
Then, change your list instance to use this definition.


About your question related to "Set Number Value", I effectively use it to force restarting level to 1.
The key is StartOverrideNumberingValue() { Val = 1 } (see NumberingListStyleCollection.BeginList())



I think, I should add a way to let you push your own list definition.
Feb 10, 2015 at 9:17 PM
Not really building a TOC, just a document with 2-3 levels of heading with some plain text and nested lists after each of the headings.

I defined numbering in the template and it applied fine, except for one issue, which I isolated to Word itself: that 2nd level headings do not re-start numbering after the 1st level headers. When I simply add a few lines to a brand new Word document, based on Normal.dotx, and apply Heading 1 and Heading 2 styles, then Heading 2 numbering is not re-started after Heading 1. So it seems that Word itself is not restarting numbering.

That might be related to behaviour of the multilevel lists I mentioned in another thread: when using "list-style-type:lower-roman" the 2nd level listings are numbered continuously throughout the document as below:
1. List item 1
2. List Item 2
  i. Nested 1
  ii. Nested 2
3. List item 3

Some text

1. List Item 1
2. List Item 2
  iii. Nested 1
  iv. Nested 2
3. List item 3
but if I am not using "list-style-type", than the 2nd nested list is numbered just 1,2,3, which is a wrong format but correctly starting at 1.
Coordinator
Feb 10, 2015 at 10:28 PM
unluckily, when dealing with numbering, this is always a pain. It's terribly bad designed.

I used this
<ol style="list-style-type: upper-alpha">
    <li>This is H1
        <ol style="list-style-type: decimal">
            <li>This is H2</li>
            <li>Another H2</li>
        </ol>
    </li>
    <li>This is another H1
        <ol style="list-style-type: decimal">
            <li>This is H2</li>
            <li>Another H2</li>
        </ol>
    </li>
    <li>Last H1
        <ol style="list-style-type: decimal">
            <li>This is H2</li>
            <li>Another H2</li>
        </ol>
    </li>
</ol>
The 2nd underlying level doesn't work. Why? This is due to my laziness : to avoid creating a new NumberDefinition each time I encounter <ol>/<ul>, I try to reuse an existing one.
Instead, MS Word will create a whole new definition with MultiLevel ad-hoc. Your sample is "easy" but what when people want to mix different list:
1.
    i.
    ii.
2.
    a.
    b.
I think, I have to start a new whole definition too and don't care if there are many list definition in the documents.
Feb 10, 2015 at 11:21 PM
onizet,

I absolutely bow before your patience in dealing with Open XML implementation, where discovering the things is such a pain.

Thanks a lot for looking into that - you are going to make so many users happy!
Feb 11, 2015 at 4:45 PM
Was just looking at the previous comment and noticed, that when using upper Alpha style, the top level list should have been A, B, C numbered.
But it appears as 1, 2, 3. Does that make sense?

onizet wrote:
unluckily, when dealing with numbering, this is always a pain. It's terribly bad designed.

I used this

<ol style="list-style-type: upper-alpha">

1.
i.
ii.
2.
a.
b.
```
and the 2nd level lists should be both same number format, but they are lower roman vs. lower alpha. That is exactly what I saw when I tried creating my own numberings.
Feb 12, 2015 at 3:56 PM
Edited Feb 12, 2015 at 4:09 PM
Should this be used instead of trying to create the numberings manually?
http://officeopenxml.com/WPnumbering-restart.php

What I mean is that every numbering level in the document should have its restart attribute equal to the the previous level by default (keeping in mind that the "restart levels" are 1 based, while the actual levels are 0 based - Confucius would be proud).

I am not so sure that creating the new numberings for every list level will be a better approach, as right now the library seems to be doing fine, except that it is not changing the list numbering formats. But it seems to be incrementing the levels consistently with the nested lists.

Only in the case where incoming nested lists are styled by the user, something is not right and a level restart described above might help.

Am I making sense?
Coordinator
Feb 16, 2015 at 1:09 PM
I don't know yet because I already use LevelOverride + StartOverrideNumberingValue.

I have to test again but for now, I have detected why my code doesn't work. I check with the previous list to know if I should nest <OL> but I don't check with the parent list.
So when I test "absNumId == prevAbsNumId", it failed.
But it doesn't restart the 2nd list and I don't succeed with LevelRestart yet...
Mar 18, 2015 at 8:21 PM
Was wondering if you got a chance to implement this update?

Thanks