Compact XSLT code to drop N number of tags if all are null

This is my xml input:

<root>
   <node1/>
   <node2/>
   <node3/>
   <node4/>
   <othertags/>
</root>

The output should be:

<root>
   <othertags/>
</root>

if any of the 4 nodes is non-zero, none of the tags should be removed.
example:

<root>
   <node1/>
   <node2/>
   <node3/>
   <node4>sample_text</node4>
   <othertags/>
</root>

Then the output should be the same as the input xml file.

<root>
   <node1/>
   <node2/>
   <node3/>
   <node4>sample_text</node4>
   <othertags/>
</root>

This is the XSL code I developed:

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
<xsl:template match="/root/node1[.='' and ../node2/.='' and ../node3/.='' and ../node4/.='']
             |/root/node2[.='' and ../node1/.='' and ../node3/.='' and ../node4/.='']
             |/root/node3[.='' and ../node1/.='' and ../node2/.='' and ../node4/.='']
             |/root/node4[.='' and ../node1/.='' and ../node2/.='' and ../node3/.='']"/>

As you can see, the code takes more effort and becomes more cumbersome as the number of nodes increases. Is there an alternative way to overcome this bottleneck?

+3
source share
4 answers

Have you tried (untested)

<xsl:template match="node1|node2|node3|node4">
  <xsl:if test="
    (preceding-sibling::*|.|following-sibling::*)[
      self::node1 or self::node2 or self::node3 or self::node4
    ][.!='']
  ">
    <xsl:copy-of select="." />
  </if>
</xsl:template>
+2
source

"--" , "not-the-nodes" . , `` 'root'.

<xsl:template match="root">
    <xsl:copy>
        <xsl:apply-templates mode="filter-those-nodes"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*" mode="filter-those-nodes">
    <xsl:choose>
        <xsl:when test="'' = concat(node1, node2, node3, node4)">
            <xsl:apply-templates mode="filter-those-nodes"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:apply-templates/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="node1 | node2 | node3 | node4" mode="not-those-nodes">
    <!-- filtered out -->
</xsl:template>

<xsl:template match="*" mode="not-those-nodes">
    <xsl:apply-templates select="." />
</xsl:template>
0

:

I. "" XSLT 1.0      

 <xsl:variable name="vNotAllEmpty" select=
  "/*/*
      [self::node1|self::node2|self::node3|self::node4]
        [not(. = '')]

  "/>

 <xsl:template match="node()|@*" name="indent">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
   "/*/*/node1|/*/*/node2|/*/*/node3|/*/*/node4">
   <xsl:if test="$vNotAllEmpty">
     <xsl:call-template name="indent"/>
   </xsl:if>
 </xsl:template>
</xsl:stylesheet>
  • ? node{N} , .

  • ? , , node{N}, , node.

II. FXSL

FXSL /, , node -set ( ).

FXSL someTrue. :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:import href="someTrue.xsl"/>

  <xsl:output omit-xml-declaration="yes"/>

    <xsl:variable name="vallNodes" select=
     "/*/*[starts-with(name(), 'node')]"/>

    <xsl:variable name="vNotAllEmpty">
     <xsl:call-template name="someTrue">
       <xsl:with-param name="pList"
          select="$vallNodes"/>
     </xsl:call-template>
    </xsl:variable>

 <xsl:template match="node()|@*" name="indent">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="*">
   <xsl:variable name="visInspectedNode" select=
    "count(.|$vallNodes) = count($vallNodes)"/>
   <xsl:if test=
      "not($visInspectedNode)
      or
        ($visInspectedNode and string($vNotAllEmpty))
      ">
      <xsl:call-template name="indent"/>
   </xsl:if>
 </xsl:template>
</xsl:stylesheet>

:

  • The nodes to be processed (stored in $vallNodes) can be hundreds or thousands.

  • The solution is very extensible. We can check whether all or some nodes satisfy the given condition using the FXSL allTruePand someTrueP.

  • The logic of scanning all nodes and accumulating the truth value is stored in these templates, and you never encode this logic - therefore, there is no extra time in vain and there is no way to make mistakes.

0
source
<xsl:template match="/root/node()[name()='node1' or name()='node2' or name()='node3' or name()='node4']
[../node1/.='' and ../node2/.='' and ../node3/.='' and ../node4/.='']"/>
0
source

Source: https://habr.com/ru/post/1738321/


All Articles