Xml XSLT用匹配规则替换条件逻辑

Xml XSLT用匹配规则替换条件逻辑,xml,xslt,Xml,Xslt,我有一个XSLT样式表,它以错误的顺序调用模板。它不是按段落和表格的显示顺序呈现段落和表格,而是呈现所有段落,然后是所有表格。我猜这个问题可以通过用模式匹配代替条件逻辑来解决,但我很难弄清楚如何做到这一点 完整的XSLT如下所示: <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output indent="yes" method="html"/>

我有一个XSLT样式表,它以错误的顺序调用模板。它不是按段落和表格的显示顺序呈现段落和表格,而是呈现所有段落,然后是所有表格。我猜这个问题可以通过用模式匹配代替条件逻辑来解决,但我很难弄清楚如何做到这一点

完整的XSLT如下所示:

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

   <xsl:template match="/*">
        <html>
            <head></head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="richtext">
        <xsl:if test="par">
            <xsl:apply-templates select="." mode="par" />
        </xsl:if>
        <xsl:if test="table">
            <xsl:apply-templates select="." mode="table" />
        </xsl:if>
    </xsl:template>

    <xsl:template match="richtext" mode="par">
        <xsl:for-each-group select="par[run[normalize-space()]]" group-adjacent="if (@def) then @def else preceding-sibling::par[run[normalize-space()]][@def][1]/@def">
            <xsl:variable name="listType" select="preceding-sibling::*[1][self::pardef]/@list" />
            <xsl:choose>
                <xsl:when test="$listType = 'bullet'">    
                    <ul>
                        <xsl:apply-templates select="current-group()" mode="list"/>
                    </ul>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()" mode="para" />   
                </xsl:otherwise>     
            </xsl:choose>   
        </xsl:for-each-group>
    </xsl:template>

    <xsl:template match="richtext" mode="table">
        <table border="1">
            <xsl:for-each select="table/tablerow">
                <tr>
                    <xsl:for-each select="tablecell">
                        <td>
                            <xsl:apply-templates />
                        </td>
                    </xsl:for-each>
                </tr>
            </xsl:for-each>
        </table>  
    </xsl:template>

    <xsl:template match="par" mode="list">
        <li>
            <xsl:apply-templates select="run" />
        </li>  
    </xsl:template>

    <xsl:template match="par" mode="para">
        <p>
            <xsl:apply-templates select="run" />
        </p>  
    </xsl:template>

    <xsl:template match="run">
         <xsl:value-of select="text()" separator=""/>
    </xsl:template>

</xsl:stylesheet>

  • 以下是XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <document>
        <item name="Some richtext">
            <richtext>
                <pardef/>
                <par def="20">
                    <run>This is a </run>
                    <run>paragraph.</run>
                </par>
                <table>
                    <tablerow>
                        <tablecell>
                            <par def="43"><run>This is a table</run></par></tablecell>
                        <tablecell>
                            <par def="44"><run>This is some data</run></par></tablecell>
                    </tablerow>
                </table>
                <pardef id="21" list="bullet"/>
                <par def="21">
                    <run>This is a </run>
                    <run>bullet point.</run>
                </par>
                <table>
                    <tablerow>
                        <tablecell>
                            <par def="43"><run>This is another table</run></par></tablecell>
                        <tablecell>
                            <par def="44"><run>This is some data</run></par></tablecell>
                    </tablerow>
                </table>
            </richtext>
        </item>
    </document>
    
    
    这是一个
    段落
    这是一张桌子
    这是一些数据
    这是一个
    要点。
    这是另一张桌子
    这是一些数据
    
    这是我想要的输出:

    <html>
       <head></head>
      <body>
         <p>This is a paragraph.</p>
         <table border="1">
            <tr>
               <td>This is a table</td>
               <td>This is some data</td>
            </tr>
         </table>
         <ul>
            <li>This is a bullet point.</li>
         </ul>
         <table border="1">
               <tr>
                  <td>This is another table</td>
                  <td>This is some data</td>
               </tr>
         </table>
      </body>
    </html>
    
    
    这是一段

    这是一张桌子 这是一些数据
    • 这是一个要点
    这是另一张桌子 这是一些数据
    您的许多问题似乎都是由于试图使用@mode来完成@match的工作而造成的。一个好的经验法则是避免@mode,除非您可能多次处理同一个节点或节点类型,或者希望在不同的时间做不同的事情

    正如@michael.hor257k所说,最好让apply模板为您进行逻辑选择

    另外,您的测试也有点不可靠,只是查看是否存在richtext的table/par子级,而不是当前上下文节点是什么(这是应用模板已经为您做的):对于您的示例,xsl:if语句都是true

    下面是一些XSLT,它可以从输入中创建您想要的内容(使用XHTML而不是HTML):我最终使用了一种模式来区分列表和普通段落,但这符合上面的经验法则:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      xmlns:local="http://example.com/local" 
      exclude-result-prefixes="xs local"
      version="2.0">
    
      <xsl:output indent="yes" method="xhtml"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:key name="pars" match="par" use="preceding-sibling::pardef[1]/generate-id()"/>
    
      <xsl:template match="document">
        <html>
          <head/>
          <body>
            <xsl:apply-templates/>
          </body>
        </html>
      </xsl:template>
    
      <!-- I want to handle par using modes, so I deliberately remove any output in the default mode.  We'll make an exception for par in table later. -->
      <xsl:template match="par"/>
    
      <xsl:template match="pardef[not(@list)]">
        <!-- I'm using a key() function here just to easily return the par elements that follow this pardef
          - see the xsl:key definition above.  You could also try using @id and @def e.g. 
          <key name="pars" match="par" use="@def"/>
          and key('pars', @id) - although the first @id in your example seems to be missing!
        -->
    
        <xsl:apply-templates select="key('pars', generate-id())" mode="p"/>
      </xsl:template>
    
      <xsl:template match="pardef[@list]">
        <ul>
          <xsl:apply-templates select="key('pars', generate-id())" mode="li"/>
        </ul>
      </xsl:template>
    
      <xsl:template match="par" mode="p">
        <p>
          <!-- Any further elements don't need mode handling, so we'll return to the default mode -->
          <xsl:apply-templates mode="#default"/>
        </p>
      </xsl:template>
    
      <xsl:template match="par" mode="li">
        <li>
          <xsl:apply-templates mode="#default"/>
        </li>
      </xsl:template>
    
      <xsl:template match="table">
        <table border="1">
          <xsl:apply-templates/>
        </table>
      </xsl:template>
    
      <xsl:template match="tablerow">
        <tr>
          <xsl:apply-templates/>
        </tr>
      </xsl:template>
    
      <xsl:template match="tablecell/par">
        <td>
          <xsl:apply-templates/>
        </td>
      </xsl:template>
    
    </xsl:stylesheet>
    
    
    


  • 如果有人能告诉我为什么我必须使用generate-id()而不是just。在关键函数和定义中,我想知道-我认为这可能是我的Saxon(9.6.0.7)中的一个bug。

    老实说,这不是一个代码编写服务。你最后的9个!问题是关于同一主题的。它总是能解决给定的问题,但不能概括地解决您的项目。学习XSLT以理解给定的解决方案,而不仅仅是复制粘贴它们。我认为版主需要调查。问题实际上不是你的条件逻辑,而是带有模式“par”的模板如何工作。如果您编辑问题以显示此模板,以及“表格”模板(我知道它在前面的问题中,但问题应该是自包含的),可能会有所帮助。谢谢。嗨@uL,我其实不是新手——我在2003-2005年广泛使用XSLT,几年前又一次使用XSLT——但我变得生疏了,因为我不总是这样做。这可能并不明显,但我一直在研究答案,试图理解它们。感谢大家在我努力跟上进度时对我的支持。@b00kgrrl我不明白为什么这里需要条件逻辑。只需将模板应用到
    par
    table
    中,并为每个模板创建一个模板即可。这是一个非常优雅的解决方案。谢谢@yamahito,如果您在键定义中使用了
    use=“.”
    ,那么对于所有空
    pardef
    元素,将使用空
    的字符串值,并且将是相同的值,即空字符串。你没有说你得到了哪个结果,但是我不认为对几个
    pardef
    元素使用相同的值会对你的算法起作用。啊,这是字符串值。出于某种原因,我记错了在2中会使用与“is”比较器等效的东西。总是有新的东西要学!