Two phase processing: Do not output empty tags from phase-1 XSLT 2.0 processing

前端 未结 1 1604
被撕碎了的回忆
被撕碎了的回忆 2020-12-01 19:19

I have some complex XSLT 2.0 transformations. I\'m trying to find out if there is general purpose way to ensure that no empty tags are output. So... conceptually, a final st

相关标签:
1条回答
  • 2020-12-01 19:58

    This XSLT 2.0 transformation illustrates how multi-pass (in this case 2-pass) processing can be done:

    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
     <xsl:template match="node()|@*" mode="#all">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*" mode="#current"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match="/">
       <xsl:variable name="vPass1">
         <xsl:apply-templates/>
       </xsl:variable>
    
       <xsl:apply-templates select="$vPass1/*" mode="non-empty"/>
     </xsl:template>
    
     <xsl:template match="text()[xs:integer(.) mod 2 eq 0]"/>
    
     <xsl:template match="*[not(node())]" mode="non-empty"/>
    </xsl:stylesheet>
    

    when applied on this XML document:

    <nums>
      <num>01</num>
      <num>02</num>
      <num>03</num>
      <num>04</num>
      <num>05</num>
      <num>06</num>
      <num>07</num>
      <num>08</num>
      <num>09</num>
      <num>10</num>
    </nums>
    

    It creates a result document in the first pass (which is captured in the $vPass1 variable), in which all <num> elements with contents even integer are stripped off their content and are empty. Then, in the second pass, applied in a specific mode, all empty elements are removed.

    The result of the transformation is:

    <nums>
       <num>01</num>
       <num>03</num>
       <num>05</num>
       <num>07</num>
       <num>09</num>
    </nums>
    

    Do note the use of modes, and the special modes #all and #current.

    Update: The OP now wants in a comment to delete "recursively" "all nodes that have no non-empty descendant".

    This can be implemented simpler using no explicit recursion. Just change:

     <xsl:template match="*[not(node())]" mode="non-empty"/>
    

    to:

     <xsl:template match="*[not(descendant::text())]" mode="non-empty"/>
    
    0 讨论(0)
提交回复
热议问题