Xslt 1.0 merges empty element names

A quick question about using xslt 1.0 that you could help me. I have an XML input code that looks like below

<Root>
    <FirstName>Bob</FirstName>
    <LastName>Marley</LastName>
    <ID>BM1234</ID>
    <Songs>
        <Song>
            <EmptyElements></EmptyElements>
            <SongName>No woman no cry</SongName>
            <Year>1974</Year>
            <album></album>
            <studio></studio>
            <rating></rating>
        </Song>
    </Songs>
</Root>

The result should look like

<Root>
    <FirstName>Bob</FirstName>
    <LastName>Marley</LastName>
    <ID>BM1234</ID>
    <Songs>
        <Song>
            <EmptyElements>album, studio, rating</EmptyElements>
            <SongName>No woman no cry</SongName>
            <Year>1974</Year>
        </Song>
    </Songs>
</Root>

so there’s basically a comma-separated list of all empty elements in the EmptyElements tag.

+4
source share
2 answers

Or simply:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="Song">
    <xsl:copy>
        <EmptyElements>
            <xsl:for-each select="*[not(node() or self::EmptyElements)]">
                 <xsl:value-of select="name()"/>
                 <xsl:if test="position()!=last()">
                    <xsl:text>, </xsl:text>
                 </xsl:if>
            </xsl:for-each> 
        </EmptyElements>
        <xsl:apply-templates select="*[node()]"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Note:

This solution proudly uses the feature last(). There are no performance issues associated with using this feature.

The XPath specification states:

The last function returns a number equal to the size of the context from the evaluation context of the expression.

And the XSLT specification tells us that:

.... :

• a node ( node)
 • ( )
  ...

, node, , node . ( xsl:for-each, xsl:apply-templates), .

: 10 . , :

<xsl:for-each select="item">
    <xsl:value-of select="position()!=last()"/>
</xsl:for-each>

<xsl:for-each select="item">
    <xsl:value-of select="not(position() = 1)"/>
</xsl:for-each>

( libxslt, Xalan Saxon).

+3

:

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

  <xsl:template match="EmptyElements" priority="5">
    <xsl:copy>
      <xsl:apply-templates mode="enumerate" select=
      "../*[not(self::EmptyElements) and not(node())]" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Songs/Song/*" mode="enumerate">
    <xsl:value-of select="substring(',', not(position() = 1), 1)"/>
    <xsl:value-of select="name()"/>
  </xsl:template>
  <xsl:template match="Songs/Song/*[not(node())]"/>
</xsl:stylesheet>

XML-:

<Root>
    <FirstName>Bob</FirstName>
    <LastName>Marley</LastName>
    <ID>BM1234</ID>
    <Songs>
        <Song>
            <EmptyElements></EmptyElements>
            <SongName>No woman no cry</SongName>
            <Year>1974</Year>
            <album></album>
            <studio></studio>
            <rating></rating>
        </Song>
    </Songs>
</Root>

, :

<Root>
   <FirstName>Bob</FirstName>
   <LastName>Marley</LastName>
   <ID>BM1234</ID>
   <Songs>
      <Song>
         <EmptyElements>album,studio,rating</EmptyElements>
         <SongName>No woman no cry</SongName>
         <Year>1974</Year>
      </Song>
   </Songs>
</Root>

  • , , node "as-is"
  • Songs/Song/*[not(node())], , , "" ( ) node .
  • EmptyElements , , EmptyElements.
  • EmptyElements , () enumerate siblings-.
  • , enumerate Song, Songs. <xsl:apply-templates> 4. EmptyElements. : a) , node node -list; b) . - EmptyElements, .

, , Or simply: , .

, , , Or simply: -answer, , , . . Or simply: -:

enter image description here

Or simply: - - . :

             <xsl:if test="position()!=last()">
                <xsl:text>, </xsl:text>
             </xsl:if>

, :

not(position() = 1)

. Dr. , " ", , , :

"? , , last() : - . " position() ne last()" , , , 1.

, , ( ).

: , - : "Or simply:", , ...

+1

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


All Articles