如何在ASP.net中使用Open XML创建多级有序列表? [英] How do you create multi-level ordered lists with Open XML in ASP.net?

查看:126
本文介绍了如何在ASP.net中使用Open XML创建多级有序列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我花了无数小时试图了解Open XML中的有序列表.这是

I've spent countless hours trying to understand ordered lists in Open XML. Here's one of many references.

我在此处找到了一个简单的文档创建者非常有用的示例.

I found this incredibly helpful example of a simple document creator here.

此外,如果我可以稍加放松,我必须说这是一个痛苦的学习过程.创建编号属性并引用正确的abstractNumberId,列表将不断出现.

Also if I may gripe a little bit, I must say this is a painful learning curve. Creating numbering properties and referencing the correct abstractNumberId and the list goes on and on.

有人在代码中创建多级列表的完整示例吗?我可以不使用任何自定义设置来执行此操作,就像设置NumberFormatValues.Decimal一样.一旦您要开始控制listType,就会有很多即时开销.

Does anyone have a complete example of creating multi-level lists in code? I can do so with no custom settings, as in setting the NumberFormatValues.Decimal. As soon as you want to start controlling the listType you have a lot of instant overhead.

以上面的示例为例,我添加了一个level参数:

Taking the above example that I started with, I added a level argument:

public void AddBulletList(List<Run> runList, int level)

我将其合并到这一行:

var abstractLevel = new Level(new NumberingFormat() {
    Val = NumberFormatValues.Decimal}, new LevelText() {Val = "·"}) {LevelIndex = level};

请注意,我已将格式类型更改为十进制...方法名称显示了bullet,但我只是在这里进行测试.

Notice that I changed the format type to decimal... the method name says bullet but I'm just testing here.

我还利用它来处理缩进:

I also leverage it to handle the indentation:

var indentation = new Indentation() { Left = (720 * (level + 1)).ToString(), Hanging = "360" };  

因此,在我的测试中,我向通过0进行级别传递的方法发送了一些句子.然后,我再发送一些1级别的通行证.

So in my tests, I send a few sentences to the method passing in 0 for level. Then I send a few more passing in 1 for level.

我的结果有两个问题:

1)我不知道如何重置计数器,所以我得到了:

1) I can't figure out how to reset the counter, so I get this:

1. Sentence 1
2. Sentence 2
3. Sentence 3
    4. Sentence 1
    5. Sentence 2
    6. Sentence 3

我尝试使用levelRestart,但是没有用:

I attempted to use the levelRestart but that didn't work:

abstractLevel.LevelRestart = new LevelRestart(){ Val = 0 } // tried 1 also

重启的唯一方法是在插入第二个句子列表之前插入一个空白段落,但这存在样式问题(间距).

The only way I could get it to restart was to insert a blank paragraph before inserting the second list of sentences but this has styling issues (spacing).

我遇到的第二个问题是编号出现在WordDoc中,但在Microsoft Word中显示为项目符号.此外,我在Microsoft Word中收到兼容模式警告.

The second issue that I'm having is the numbering appears in WordDoc, but it shows as bullet points in Microsoft Word. In addition, I get a compatibility mode warning in Microsoft Word.

有人会说:

使用Open XML生产力工具并创建文档并查看生成的代码

Use Open XML Productivity Tools and create a doc and look at the generated code

我对此的答复是:

查看了5,000行代码后,我的眼睛开始流血,这是一个用于创建的小文档.

My eyes are bleeding after looking at the 5,000 lines of code a tiny little document to test with creates.

所以我觉得我超级亲密.我的代码中还有很多其他自定义项,这就是为什么我继续参考我的起点的原因.如果有人可以采用该示例或提供现有示例,我只想创建多级列表并控制使用的编号类型(lowerRoman,十进制等).

So I feel like I'm super close. I have a lot of other customizations in my code which is why I continue to reference where I started. If someone could take that example or provide an existing one, I simply want to create multi-level lists and control the type of numbering (lowerRoman, decimal, etc.) is used.

更新1

我真的只是硬着头皮做了一些认真的研究.在托马斯的帮助下,我得以继续前进,但看来我还有一个烦人的问题.我的新排序列表不是从"1"开始.

I've really just had to bite the bullet and do some serious studying. With Thomas' help I've been able to press forward, but it seems I have one more pesky issue. My new ordered lists do not start at "1".

请注意图像中的显示方式,如果我单击第一个列表的级别,它将仅突出显示该列表.我希望它们是分开的,但显然不是.下一个列表应从1开始.

Notice how in the image, if I click on the level for the first list, it highlights only that list. I expect them to be separate but apparently not. The next list should start at 1.

对于每个新的有序列表,我都为其分配了一个新的numberId,所以我不知道发生了什么.这是生成的标记:

For each new ordered list, I'm assigning it a new numberId so I don't know what's happening. Here's the generated markup:

<w:numbering xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid wp14">
      <w:abstractNum w:abstractNumId="1" w15:restartNumberingAfterBreak="1">
        <w:nsid w:val="191025D9" />
        <w:multiLevelType w:val="hybridMultilevel" />
        <w:tmpl w:val="48A2E570" />
        <w:lvl w:ilvl="0" w:tplc="0409000F">
          <w:start w:val="1" />
          <w:numFmt w:val="decimal" />
          <w:lvlText w:val="%1." />
          <w:lvlJc w:val="left" />
          <w:pPr>
            <w:ind w:start="720" w:hanging="360" />
          </w:pPr>
        </w:lvl>
        <w:lvl w:ilvl="1" w:tplc="04090019">
          <w:start w:val="1" />
          <w:numFmt w:val="lowerLetter" />
          <w:lvlText w:val="%2." />
          <w:lvlJc w:val="left" />
          <w:pPr>
            <w:ind w:start="1440" w:hanging="360" />
          </w:pPr>
        </w:lvl>        
      </w:abstractNum>
      <w:abstractNum w:abstractNumId="2" w15:restartNumberingAfterBreak="1">
        <w:nsid w:val="191025D9" />
        <w:multiLevelType w:val="hybridMultilevel" />
        <w:tmpl w:val="48A2E570" />
        <w:lvl w:ilvl="0" w:tplc="0409000F">
          <w:start w:val="1" />
          <w:numFmt w:val="decimal" />
          <w:lvlText w:val="%1." />
          <w:lvlJc w:val="left" />
          <w:pPr>
            <w:ind w:start="720" w:hanging="360" />
          </w:pPr>
        </w:lvl>
        <w:lvl w:ilvl="1" w:tplc="04090019">
          <w:start w:val="1" />
          <w:numFmt w:val="lowerLetter" />
          <w:lvlText w:val="%2." />
          <w:lvlJc w:val="left" />
          <w:pPr>
            <w:ind w:start="1440" w:hanging="360" />
          </w:pPr>
        </w:lvl>        
      </w:abstractNum>
      <w:num w:numId="1">
        <w:abstractNumId w:val="1" />
      </w:num>
      <w:num w:numId="2">
        <w:abstractNumId w:val="2" />
      </w:num>
    </w:numbering>

这是尸体:

    <w:body xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:p>
    <w:pPr>
      <w:pStyle w:val="ListParagraph" />
      <w:numPr>
        <w:ilvl w:val="0" />
        <w:numId w:val="1" />
      </w:numPr>
    </w:pPr>
    <w:r>
      <w:t>List one item 1</w:t>
    </w:r>
  </w:p>
  <w:p>
    <w:pPr>
      <w:pStyle w:val="ListParagraph" />
      <w:numPr>
        <w:ilvl w:val="0" />
        <w:numId w:val="1" />
      </w:numPr>
    </w:pPr>
    <w:r>
      <w:t>List one item 2</w:t>
    </w:r>
  </w:p>
  <w:p>
    <w:pPr>
      <w:pStyle w:val="ListParagraph" />
      <w:numPr>
        <w:ilvl w:val="0" />
        <w:numId w:val="2" />
      </w:numPr>
    </w:pPr>
    <w:r>
      <w:t>List two item 1</w:t>
    </w:r>
  </w:p>
  <w:p>
    <w:pPr>
      <w:pStyle w:val="ListParagraph" />
      <w:numPr>
        <w:ilvl w:val="0" />
        <w:numId w:val="2" />
      </w:numPr>
    </w:pPr>
    <w:r>
      <w:t>List two item 2</w:t>
    </w:r>
  </w:p>
</w:body>

推荐答案

虽然我从未使用过Open XML生产力工具,但我还是定期使用并推荐

While I've never used the Open XML Productivity Tools, I regularly use and recommend the Open XML Package Editor for Modern Visual Studios. With that package editor, you can look at the Open XML markup created by Microsoft Word to learn from that.

因此,为了回答您的问题,我使用包含多个多级列表的Word模板来做到这一点,这些多级列表的行为与您希望它们的行为完全一样(我希望如此).

So, to answer your question, I've done just that, using a Word template that contains several multi-level lists that behave exactly like you want them to behave (I hope).

(a)  First paragraph, on outline level 0 (shown as 1 in Word)
(b)  Second paragraph, on outline level 0
     (1) Third paragraph, on outline level 1 (shown as 2 in Word)
     (2) Fourth paragraph, on outline level 1

请注意,您在多级列表的不同级别上通常会使用不同的编号格式(例如,小写字母,大写字母,小写罗马字母,大写罗马字母,十进制).

Note that you would typically have different numbering formats (e.g., lower letter, upper letter, lower roman, upper roman, decimal) on the different levels of your multi-level list.

接下来,这是主文档部分的相应Open XML标记:

Next, this is the corresponding Open XML markup for the Main Document Part:

  <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
    <w:body>
      <w:p>
        <w:pPr>
          <w:pStyle w:val="ListLowerLetter0"/>
        </w:pPr>
        <w:r>
          <w:t>First paragraph, on outline level 0 (shown as 1 in Word)</w:t>
        </w:r>
      </w:p>
      <w:p>
        <w:pPr>
          <w:pStyle w:val="ListLowerLetter0"/>
        </w:pPr>
        <w:r>
          <w:t>Second paragraph, on outline level 0</w:t>
        </w:r>
      </w:p>
      <w:p>
        <w:pPr>
          <w:pStyle w:val="ListLowerLetter0"/>
          <w:numPr>
            <w:ilvl w:val="1"/>    <!-- This overrides the numbering level -->
            <w:numId w:val="43"/>  <!-- This references the w:numbering/w:num -->
          </w:numPr>
        </w:pPr>
        <w:r>
          <w:t>Third paragraph, on outline level 1 (shown as 2 in Word)</w:t>
        </w:r>
      </w:p>
      <w:p>
        <w:pPr>
          <w:pStyle w:val="ListLowerLetter0"/>
          <w:numPr>
            <w:ilvl w:val="1"/>
            <w:numId w:val="43"/>
          </w:numPr>
        </w:pPr>
        <w:r>
          <w:t>Fourth paragraph, on outline level 1</w:t>
        </w:r>
      </w:p>
    </w:body>
  </w:document>

请注意w:pStylew:numPr元素,它们指定要使用的编号段落样式,并且在还使用w:numPr的情况下,覆盖样式中指定的默认编号.

Note the w:pStyle and w:numPr elements, which specify the numbered paragraph style to be used and, where w:numPr is also used, override the numbering defaults specified in the style.

接下来,这是样式定义部分的Open XML标记:

Next, this is the Open XML markup for the Style Definitions Part:

  <w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">

    <!-- This is the paragraph style used in the main document part (w:document) -->
    <w:style w:type="paragraph" w:customStyle="1" w:styleId="ListLowerLetter0">
      <w:name w:val="List Lower Letter 0"/>
      <w:basedOn w:val="Normal"/>
      <w:pPr>
        <w:numPr>
          <w:numId w:val="43"/>   <!-- This references the w:numbering/w:num -->
        </w:numPr>
      </w:pPr>
    </w:style>

    <!-- This is the list style referenced in the numbering definitions part (w:numbering).
         This is optional but helps if you want to use the list in Word. -->
    <w:style w:type="numbering" w:customStyle="1" w:styleId="ListLowerLetter0List">
      <w:name w:val="List Lower Letter 0 List"/>
      <w:basedOn w:val="NoList"/>
      <w:pPr>
        <w:numPr>
          <w:numId w:val="43"/>   <!-- This references the w:numbering/w:num -->
        </w:numPr>
      </w:pPr>
    </w:style>


    <!-- I've included this for completeness because it is referenced by our
         paragraph style below -->
    <w:style w:type="paragraph" w:default="1" w:styleId="Normal">
      <w:name w:val="Normal"/>
      <w:rPr>
        <w:kern w:val="16"/>
      </w:rPr>
    </w:style>

    <!-- I've included this for completeness because it is referenced by our
         list style below -->
    <w:style w:type="numbering" w:default="1" w:styleId="NoList">
      <w:name w:val="No List"/>
      <w:semiHidden/>
      <w:unhideWhenUsed/>
    </w:style>
  </w:styles>

我真的只需要ListLowerLetter0样式. ListLowerLetter0List是可选的列表样式.我总是在模板中使用它们.其他两种样式只是为了完整性和一致性.显然,现实生活中的样式定义"部分包含更多样式和其他元素.

I would only really need the ListLowerLetter0 style. ListLowerLetter0List is an optional list style. I always use those in my templates. The other two styles are just there for completeness and consistency. Obviously, a real-life Style Definitions Part contains many more styles and other elements.

最后,我们有了编号定义部分的Open XML标记(同样有注释解释了相关元素的作用):

Finally, we have the Open XML markup of the Numbering Definitions Part (again with comments explaining what the relevant elements do):

  <w:numbering xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
               xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
               xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
               xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
               mc:Ignorable="w14 w15">

    <!-- Here's an example multi-level list -->
    <w:abstractNum w:abstractNumId="67" w15:restartNumberingAfterBreak="0">
      <w:nsid w:val="3E434843" />
      <w:multiLevelType w:val="multilevel" />
      <w:tmpl w:val="1146F302" />

      <!-- The w:styleLink references our list style. This is optional (but I use
           it as a best practice in Word) -->
      <w:styleLink w:val="ListLowerLetter0List" />

      <!-- This defines the first outline level, i.e., 0 in Open XML lingo or 1
           when you look at it in Word -->
      <w:lvl w:ilvl="0">
        <!-- This starts the level at the ordinal number 1, i.e., "a" on this level -->
        <w:start w:val="1" />

        <!-- This defines the number format on this level -->
        <w:numFmt w:val="lowerLetter" />

        <!-- This references our paragraph style, which will be the same on each level -->
        <w:pStyle w:val="ListLowerLetter0" />

        <!-- This defines the level text, e.g., (a), (b), (c), ... -->
        <w:lvlText w:val="(%1)" />

        <!-- The next elements define alignment, indentation, and color -->
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="851" w:hanging="851" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>

      <!-- This and the following w:lvl elements define levels 1 to 8 (i.e., 2 to 9 in Word) -->
      <w:lvl w:ilvl="1">
        <w:start w:val="1" />
        <w:numFmt w:val="decimal" />
        <w:lvlText w:val="(%2)" />
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="1418" w:hanging="567" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>
      <w:lvl w:ilvl="2">
        <w:start w:val="1" />
        <w:numFmt w:val="upperLetter" />
        <w:lvlText w:val="(%3)" />
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="1985" w:hanging="567" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>
      <w:lvl w:ilvl="3">
        <w:start w:val="1" />
        <w:numFmt w:val="lowerRoman" />
        <w:lvlText w:val="(%4)" />
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="2552" w:hanging="567" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>
      <w:lvl w:ilvl="4">
        <w:start w:val="1" />
        <w:numFmt w:val="lowerLetter" />
        <w:lvlText w:val="%5." />
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="3119" w:hanging="567" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>
      <w:lvl w:ilvl="5">
        <w:start w:val="1" />
        <w:numFmt w:val="decimal" />
        <w:lvlText w:val="%6." />
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="3686" w:hanging="567" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>
      <w:lvl w:ilvl="6">
        <w:start w:val="1" />
        <w:numFmt w:val="lowerLetter" />
        <w:lvlText w:val="%7." />
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="4253" w:hanging="567" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>
      <w:lvl w:ilvl="7">
        <w:start w:val="1" />
        <w:numFmt w:val="lowerRoman" />
        <w:lvlText w:val="%8." />
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="4820" w:hanging="567" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>
      <w:lvl w:ilvl="8">
        <w:start w:val="1" />
        <w:numFmt w:val="lowerLetter" />
        <w:lvlText w:val="%9)" />
        <w:lvlJc w:val="left" />
        <w:pPr>
          <w:ind w:left="5387" w:hanging="567" />
        </w:pPr>
        <w:rPr>
          <w:color w:val="auto" />
        </w:rPr>
      </w:lvl>
    </w:abstractNum>

    <!-- This is the w:num referenced from our main document part (w:document) -->
    <w:num w:numId="43">
      <w:abstractNumId w:val="67" />
    </w:num>
  </w:numbering>

现在,基于对创建所需效果所需的标记的理解,使用以下两种方法之一来手工编写生成该标记的C#代码实际上非常容易:

Now, based on the understanding of the markup required to create the desired effect, it is actually pretty easy to hand-write C# code that produces that markup, using either:

  • the strongly typed classes of the Open XML SDK or
  • Linq to XML as used in the Open-XML-PowerTools.

让我为这两个选项提供非常简短的示例,并产生以下标记:

Let me provide very short examples for both options, producing the following markup:

    <w:num w:numId="43">
      <w:abstractNumId w:val="67" />
    </w:num>

以下是使用 Open XML SDK 的强类型类的代码:

Here's the code that uses the strongly typed classes of the Open XML SDK:

var num = new NumberingInstance
{
    NumberID = 43,
    AbstractNumId = new AbstractNumId { Val = 67 }
};

这是使用 Open-XML-PowerTools 的代码:

And here's the code that uses the Open-XML-PowerTools:

var num =
    new XElement(W.num, new XAttribute(W.numId, 43),
        new XElement(W.abstractNumId, new XAttribute(W.val, 67)));

在这种情况下,Open-XML-PowerTools的优点在于您可以从字面上复制标签名称.此外,Linq to XML类的构造函数(例如XElement)比Open XML SDK的构造函数灵活得多,并且C#代码看起来很像Open XML标记.因此,对于这样的用例,我稍微偏爱Open-XML-PowerTools.但是,在这种情况下,我也非常成功地使用了Open XML SDK.

In this case, the beauty of the Open-XML-PowerTools is that you can literally copy the tag names. Further, the constructors of the Linq to XML classes (e.g., XElement) are much more flexible than those of the Open XML SDK and the C# code looks much like the Open XML markup. Therefore, I have a slight preference for the Open-XML-PowerTools for use cases like this. However, I've very successfully used the Open XML SDK for such cases as well.

这篇关于如何在ASP.net中使用Open XML创建多级有序列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆