如何在 XSLT 的前兄弟中测试多个条件

How to test for multiple conditions in previous-sibling in XSLT

我有 XML 数据是从遗留的 Lotus Notes 应用程序中提取的,并且嵌入了富文本格式。我试图根据出现在前一个兄弟姐妹中的属性来格式化每个文本块。我的 XSLT 受到来自@Jayvee 的 的启发,但它不起作用。

这是XML:

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <item name="Unordered list">
        <richtext>
            <pardef/>
            <par def="20">
                <run>This is the first </run><run>paragraph of the preamble.</run>
            </par>
            <par>
                <run>This is the second paragraph of the </run><run>preamble.</run>
            </par>
            <pardef id="21" list="unordered"/>
            <par def="21">
                <run>This is the </run><run>first bullet.</run>
            </par>
            <par>
                <run>This is the second </run><run>bullet.</run>
            </par>
            <par def="20">
                <run>This is the first </run><run>paragraph of the conclusion.</run>
            </par>
            <par>
                <run>This is the second paragraph of the </run><run>conclusion.</run>
            </par>
        </richtext>
    </item>
    <item name="Ordered list">
        <richtext>
            <pardef/>
            <par def="20">
                <run>This is the first </run><run>paragraph of the preamble.</run>
            </par>
            <par>
                <run>This is the second paragraph of the </run><run>preamble.</run>
            </par>
            <pardef id="46" list="ordered"/>
            <par def="46">
                <run>This is the </run><run>first numbered item.</run>
            </par>
            <par>
                <run>This is the another </run><run>numbered item.</run>
            </par>
            <par def="20">
                <run>This is the first </run><run>paragraph of the conclusion.</run>
            </par>
            <par>
                <run>This is the second paragraph of the </run><run>conclusion.</run>
            </par>
        </richtext>
    </item>
</document>

这是期望的输出:

<html>
  <body>
     <table border="1">
        <tr>
           <td>Unordered list</td>
           <td>
              <p>This is the first paragraph of the preamble.</p>
              <p>This is the second paragraph of the preamble.</p>
              <ul>
                 <li>This is the first bullet.</li>
                 <li>This is the second bullet.</li>
              </ul>
              <p>This is the first paragraph of the conclusion.</p>
              <p>This is the second paragraph of the conclusion.</p>
           </td>
        </tr>
        <tr>
           <td>Ordered list</td>
           <td>
              <p>This is the first paragraph of the preamble.</p>
              <p>This is the second paragraph of the preamble.</p>
              <ol>
                 <li>This is the first numbered item.</li>
                 <li>This is the another numbered item.</li>
              </ol>
              <p>This is the first paragraph of the conclusion.</p>
              <p>This is the second paragraph of the conclusion.</p>
           </td>
        </tr>
     </table>
  </body>

这是 XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>

    <xsl:template match="/*">
        <html>
            <body>
                <table border="1">
                        <xsl:apply-templates/>
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="item">
        <tr>
            <td><xsl:value-of select="@name"/></td>
            <td>
                <xsl:apply-templates/>
            </td>
        </tr>
    </xsl:template>

    <xsl:template match="par">

        <xsl:choose>
        <xsl:when test="preceding-sibling::pardef[@list] = 'unordered' and preceding-sibling::par[@def][1][@def] != preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes">&lt;/ul&gt;</xsl:text></xsl:when>
        <xsl:when test="preceding-sibling::pardef[@list] = 'ordered' and preceding-sibling::par[@def][1][@def] != preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes">&lt;/ol&gt;</xsl:text></xsl:when>  
        </xsl:choose>

        <xsl:choose>

            <xsl:when test="@def=preceding-sibling::pardef[@id] or (not(@def) and preceding-sibling::par[@def][1][@def=preceding-sibling::pardef[@id]])">    
                <xsl:choose>
                    <xsl:when test="preceding-sibling::pardef[@list] = 'unordered' and preceding-sibling::par[@def][1][@def] = preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes">&lt;ul&gt;</xsl:text></xsl:when>
                    <xsl:when test="preceding-sibling::pardef[@list] = 'ordered' and preceding-sibling::par[@def][1][@def] = preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes">&lt;ol&gt;</xsl:text></xsl:when>  
                </xsl:choose>
                <li>
                    <xsl:for-each select="run">
                        <xsl:value-of select="text()" separator=""/>
                    </xsl:for-each>
                </li>   
            </xsl:when>

            <xsl:when test="not(@def=preceding-sibling::pardef[@id])">
                <p>
                    <xsl:for-each select="run">
                        <xsl:value-of select="text()" separator=""/>
                    </xsl:for-each>
                </p>    
            </xsl:when>     

        </xsl:choose>   

    </xsl:template>
</xsl:stylesheet>

上一题中的做法是disable-output-escaping输出开始和结束标签,这不是一个理想的做法。

相反,考虑使用一个键将 par 个元素组合在一起,第一个 par 元素具有 def 属性

<xsl:key name="pars" 
         match="par[not(@def)]" 
         use="generate-id(preceding-sibling::par[@def][1])" />

而且,假设您在 par 元素上匹配 def 属性,您可以像这样使用键:

<xsl:variable name="group" select="self::* | key('pars', generate-id())" />

要确定是否将组包装在 ulol 标记中,您可以按如下方式获取列表类型:

<xsl:variable name="listType" select="preceding-sibling::*[1][self::pardef]/@list" />

然后您可以对此进行测试以确定是否将组包装在列表标记中。

试试这个 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>

    <xsl:key name="pars" match="par[not(@def)]" use="generate-id(preceding-sibling::par[@def][1])" />

    <xsl:template match="/*">
        <html>
            <body>
                <table border="1">
                        <xsl:apply-templates />
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="item">
        <tr>
            <td><xsl:value-of select="@name"/></td>
            <td>
                <xsl:apply-templates select="richtext/par[@def]" />
            </td>
        </tr>
    </xsl:template>

    <xsl:template match="par[@def]">
        <xsl:variable name="listType" select="preceding-sibling::*[1][self::pardef]/@list" />
        <xsl:variable name="group" select="self::* | key('pars', generate-id())" />
        <xsl:choose>
            <xsl:when test="$listType = 'unordered'">    
                <ol>
                    <xsl:apply-templates select="$group" mode="list"/>
                </ol>
            </xsl:when>
            <xsl:when test="$listType = 'ordered'">    
                <ul>
                    <xsl:apply-templates select="$group"  mode="list"/>
                </ul>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="$group" mode="para" />   
            </xsl:otherwise>     
        </xsl:choose>   
    </xsl:template>

    <xsl:template match="par" mode="list">
        <li>
            <xsl:value-of select="run" separator=""/>
        </li>  
    </xsl:template>

    <xsl:template match="par" mode="para">
        <para>
            <xsl:value-of select="run" separator=""/>
        </para>  
    </xsl:template>
</xsl:stylesheet>