我们如何使用XSLT将Microsoft Word DOCX文件中的嵌套列表转换为HTML?

时间:2017-03-21 16:25:36

标签: xml xslt

<w:p w:rsidR="008845A9" w:rsidRPr="001509B0" w:rsidRDefault="008845A9" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
        </w:pPr>
    </w:p>
    <w:p w:rsidR="001207E2" w:rsidRPr="001509B0" w:rsidRDefault="001207E2" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
            <w:numPr>
                <w:ilvl w:val="1"/>
                <w:numId w:val="5"/>
            </w:numPr>
        </w:pPr>
        <w:r w:rsidRPr="001509B0">
            <w:t>First Item</w:t>
        </w:r>
    </w:p>
    <w:p w:rsidR="00AD36E6" w:rsidRPr="001509B0" w:rsidRDefault="00AD36E6" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
            <w:numPr>
                <w:ilvl w:val="1"/>
                <w:numId w:val="5"/>
            </w:numPr>
        </w:pPr>
        <w:r w:rsidRPr="001509B0">
            <w:t>Second Item</w:t>
        </w:r>
    </w:p>
    <w:p w:rsidR="00AD36E6" w:rsidRPr="001509B0" w:rsidRDefault="00AD36E6" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
            <w:numPr>
                <w:ilvl w:val="1"/>
                <w:numId w:val="5"/>
            </w:numPr>
        </w:pPr>
        <w:r w:rsidRPr="001509B0">
            <w:t>Third Item</w:t>
        </w:r>
    </w:p>
    <w:p w:rsidR="002B7A91" w:rsidRPr="001509B0" w:rsidRDefault="002B7A91" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
            <w:numPr>
                <w:ilvl w:val="2"/>
                <w:numId w:val="5"/>
            </w:numPr>
        </w:pPr>
        <w:r w:rsidRPr="001509B0">
            <w:t>Third Item – One</w:t>
        </w:r>
    </w:p>
    <w:p w:rsidR="002B7A91" w:rsidRPr="001509B0" w:rsidRDefault="002B7A91" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
            <w:numPr>
                <w:ilvl w:val="2"/>
                <w:numId w:val="5"/>
            </w:numPr>
        </w:pPr>
        <w:r w:rsidRPr="001509B0">
            <w:t xml:space="preserve">Third Item </w:t>
        </w:r>
        <w:r w:rsidR="006551A3" w:rsidRPr="001509B0">
            <w:t>–</w:t>
        </w:r>
        <w:r w:rsidRPr="001509B0">
            <w:t xml:space="preserve"> Two</w:t>
        </w:r>
    </w:p>
    <w:p w:rsidR="006551A3" w:rsidRPr="001509B0" w:rsidRDefault="006551A3" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
            <w:numPr>
                <w:ilvl w:val="3"/>
                <w:numId w:val="6"/>
            </w:numPr>
        </w:pPr>
        <w:r w:rsidRPr="001509B0">
            <w:t xml:space="preserve">Sample Item </w:t>
        </w:r>
        <w:r w:rsidR="00554D9D" w:rsidRPr="001509B0">
            <w:t>A</w:t>
        </w:r>
    </w:p>
    <w:p w:rsidR="006551A3" w:rsidRPr="001509B0" w:rsidRDefault="00554D9D" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
            <w:numPr>
                <w:ilvl w:val="3"/>
                <w:numId w:val="6"/>
            </w:numPr>
        </w:pPr>
        <w:r w:rsidRPr="001509B0">
            <w:t>Sample Item B</w:t>
        </w:r>
    </w:p>
    <w:p w:rsidR="002B7A91" w:rsidRPr="001509B0" w:rsidRDefault="002B7A91" w:rsidP="004E414C">
        <w:pPr>
            <w:pStyle w:val="AppBody-Description"/>
            <w:numPr>
                <w:ilvl w:val="1"/>
                <w:numId w:val="5"/>
            </w:numPr>
        </w:pPr>
        <w:r w:rsidRPr="001509B0">
            <w:t>Fo</w:t>
        </w:r>
        <w:r w:rsidR="00565721" w:rsidRPr="001509B0">
            <w:t>u</w:t>
        </w:r>
        <w:r w:rsidRPr="001509B0">
            <w:t>rth Item</w:t>
        </w:r>
    </w:p>

嗨,这是Microsoft Word DOCX的XML文件代码的一部分,这些列表是如上所示嵌套的。

1.First Item
2.Second Item
3.Third Item
    i.Third Item – One
    ii.Third Item – Two
       a.Sample Item A
       b.Sample Item B
4.Fourth Item

而不是这个数字,我得到的结果就像;

•First Item
•Second Item
•Third Item
•Third Item – One
•Third Item – Two
•Sample Item A
•Sample Item B
•Fourth Item

这是我在XSLT中通过使用<ul><li>解决此问题的解决方案,但我想我需要在这里实现不同的东西。我不知道该怎么做,其余的很好,我可以处理表部件等。但嵌套列表现在是问题。

<xsl:output method="html" doctype-system="about:legacy-compat"/>
    <xsl:template match="/">
        <html>
            <head>
                <title/>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
        </xsl:template>
        <xsl:template match="w:p">
            <xsl:if test="w:pPr/w:pStyle[@w:val='AppBody-Title']">
                <h1>
                    <xsl:apply-templates select="w:r/w:t"/>
                </h1>
            </xsl:if>
            <xsl:if test="w:pPr/w:pStyle[@w:val='AppBody-Description']">
                    <xsl:choose>
                        <xsl:when test="w:pPr/w:numPr">
                        <ul>
                            <li><xsl:apply-templates select="w:r/w:t"/></li>
                        </ul>
                        </xsl:when>
                        <xsl:otherwise>
                        <p>
                            <xsl:apply-templates select="w:r/w:t"/>
                        </p>
                        </xsl:otherwise>
                    </xsl:choose>
            </xsl:if>
            <xsl:if test="w:pPr/w:pStyle[@w:val='AppBody-Claim']">
                <p>
                    <xsl:apply-templates select="w:r/w:t"/>
                </p>
            </xsl:if>
            <xsl:if test="w:pPr/w:spacing[@w:line='360']">
                <p>
                    <xsl:apply-templates select="w:r/w:t"/>
                </p>
            </xsl:if>
            <xsl:if test="w:pPr/w:pStyle[@w:val='AppBody-Heading']">
                <h2>
                    <xsl:apply-templates select="w:r/w:t"/>
                </h2>
            </xsl:if>
        </xsl:template>
</xsl:stylesheet>

*我找到了解决方案*

<xsl:output method="html" doctype-system="about:legacy-compat"/>
    <xsl:template match="/">
        <html>
            <head>
                <title/>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
        </xsl:template>
        <xsl:template match="w:p">
            <xsl:if test="w:pPr/w:pStyle[@w:val='AppBody-Title']">
                <h1>
                    <xsl:apply-templates select="w:r/w:t"/>
                </h1>
            </xsl:if>
            <xsl:if test="w:pPr/w:pStyle[@w:val='AppBody-Description']">
                    <xsl:choose>
                        <xsl:when test="w:pPr/w:numPr/w:ilvl[@w:val='1']">
                        <ul>
                            <li><xsl:apply-templates select="w:r/w:t"/></li>
                        </ul>
                        </xsl:when>
                        <xsl:when test="w:pPr/w:numPr/w:ilvl[@w:val='2']">
                        <ul>
                            <ul>
                                <li><xsl:apply-templates select="w:r/w:t"/></li>
                            </ul>
                        </ul>
                        </xsl:when>
                        <xsl:when test="w:pPr/w:numPr/w:ilvl[@w:val='3']">
                        <ul>
                            <ul>
                                <ul>
                                    <li><xsl:apply-templates select="w:r/w:t"/></li>
                                </ul>
                            </ul>
                        </ul>
                        </xsl:when>
                        <xsl:otherwise>
                        <p>
                            <xsl:apply-templates select="w:r/w:t"/>
                        </p>
                        </xsl:otherwise>
                    </xsl:choose>
            </xsl:if>
            <xsl:if test="w:pPr/w:pStyle[@w:val='AppBody-Claim']">
                <p>
                    <xsl:apply-templates select="w:r/w:t"/>
                </p>
            </xsl:if>
            <xsl:if test="w:pPr/w:spacing[@w:line='360']">
                <p>
                    <xsl:apply-templates select="w:r/w:t"/>
                </p>
            </xsl:if>
            <xsl:if test="w:pPr/w:pStyle[@w:val='AppBody-Heading']">
                <h2>
                    <xsl:apply-templates select="w:r/w:t"/>
                </h2>
            </xsl:if>
        </xsl:template>
</xsl:stylesheet>

*但这不是一个自动解决方案。例如,如果不同文档中有另一个图层,则无法正常工作。

我们如何自动选择数字“1”到“..”?

1 个答案:

答案 0 :(得分:2)

中隐藏着这个问题的答案

XSLT transformation of boolean expressions

但由于周围有很多噪音,我会提取相关部分。

给定一系列具有级别编号的元素:

<a level="1"/>
<b level="2"/>
<c level="3"/>
<d level="3"/>
<e level="2"/>

我们可以将它们变成树形结构

<a><b><c/><d/></b><e/></a>

使用递归分组如下。我们编写一个模板,进行一级分组,然后递归调用自己进行下一级:

<xsl:template name="grouping">
  <xsl:param name="input" as="element()*"/>
  <xsl:if test="exists($input)">
    <xsl:variable name="level" select="$input[1]/@level"/>
    <xsl:for-each-group select="$input" 
                        group-starting-with="*[@level=$level]">
      <xsl:copy>
        <xsl:call-template name="grouping">
           <xsl:with-param name="input" 
                           select="current-group()[position() gt 1]"/>
        </xsl:call-template>
      </xsl:copy>
    </xsl:for-each-group>
  </xsl:if>
</xsl:template>

使用XSLT 2.0。使用XSLT 1.0的解决方案将变得更加困难。

当然,与我的小样本相比,你的输入有很多M $噪音。但问题的结构是一样的。