Home > Enterprise >  XSLT - Merge 2 elements and add some other elements instead of one of them
XSLT - Merge 2 elements and add some other elements instead of one of them

Time:01-15

Good morning,

What I want to do: I have the following xml (it's a part of the xml, not the complete)

<?xml version="1.0" encoding="UTF-8" ?>
<tv generator-info-name="Takealug EPG Grabber Ver. 1.1.2 matrix" generator-info-url="https://github.com/DeBaschdi/service.takealug.epg-grabber">

<!--  CHANNEL LIST -->
<channel id="Warner TV Film">
        <display-name lang="ch">Warner TV Film</display-name>
    </channel>
    <channel id="Warner TV Serie HD">
        <display-name lang="de">Warner TV Serie HD</display-name>
    </channel>

<!--  PROGRAMME LIST -->
   <programme start="20220111114500  0000" stop="20220111143500  0000" channel="Warner TV Film">
        <title lang="ch">Der Soldat James Ryan</title>
        <desc lang="ch">(US) 1997 • FSK 16 • IMDb:★★★★☆
        Captain John Miller soll den Soldaten James Ryan finden und lebend in Sicherheit bringen, um seiner Mutter den letzten Sohn zu retten.</desc>
        <date>1997</date>
        <category lang="ch">Adventure / Western / War</category>
        <country>US</country>
        <rating>
            <value>16</value>
        </rating>
        <star-rating system="IMDb">
            <value>8.6/10</value>
        </star-rating>
    </programme>

    <programme start="20220112222500  0000" stop="20220112231500  0000" channel="Warner TV Serie HD">
        <title lang="de">Lethal Weapon</title>
        <sub-title lang="de">Mein Plan, dein Plan</sub-title>
        <desc lang="de"> 2016 • S1 E3 • FSK 12
        Riggs und Murtaugh bekommen es mit einem Drogenkartell zu tun. Wie es scheint, ist auch Murtaughs ehemaliger Ausbilder Ned Brower in die Geschichte verwickelt. Als der Fall zu schwierig für sie wird, holt das Duo ihren Kollegen Cruz als Verstärkung an Bord. Riggs kommt nicht mit Mirandas Tod zurecht, während Murtaugh und Trish Probleme haben, einmal Zeit für Zweisamkeit zu finden.</desc>
        <date>2016</date>
        <category lang="de">Drama (Serie)</category>
        <category lang="de">Action</category>
        <episode-num system="onscreen">S1 E3</episode-num>
        <rating>
            <value>12</value>
        </rating>
    </programme>
</tv>

What i wanted to have as output:

<tv generator-info-name="Takealug EPG Grabber Ver. 1.1.2 matrix"
    generator-info-url="https://github.com/DeBaschdi/service.takealug.epg-grabber"><!--  CHANNEL LIST -->
   <channel id="Warner TV Film">
      <display-name lang="ch">Warner TV Film</display-name>
   </channel>
   <channel id="Warner TV Serie HD">
      <display-name lang="de">Warner TV Serie HD</display-name>
   </channel>
   <!--  PROGRAMME LIST -->
   <programme start="20220111114500  0000"
              stop="20220111143500  0000"
              channel="Warner TV Film">
      <sub-title>Adventure / Western / War | 1997 | US | FSK: 16</sub-title>
      <title lang="ch">Der Soldat James Ryan</title>
      <desc lang="ch">(US) 1997 • FSK 16 • IMDb:★★★★☆
        Captain John Miller soll den Soldaten James Ryan finden und lebend in Sicherheit bringen, um seiner Mutter den letzten Sohn zu retten.</desc>
      <rating>
         <value>16</value>
      </rating>
      <star-rating system="IMDb">
         <value>8.6/10</value>
      </star-rating>
   </programme>
   <programme start="20220112222500  0000"
              stop="20220112231500  0000"
              channel="Warner TV Serie HD">
      <sub-title>S1 E3 | Drama (Serie) | Action | 2016 | FSK: 12</sub-title>
      <title lang="de">Lethal Weapon: Mein Plan, dein Plan</title>
      <desc lang="de"> 2016 • S1 E3 • FSK 12
        Riggs und Murtaugh bekommen es mit einem Drogenkartell zu tun. Wie es scheint, ist auch Murtaughs ehemaliger Ausbilder Ned Brower in die Geschichte verwickelt. Als der Fall zu schwierig für sie wird, holt das Duo ihren Kollegen Cruz als Verstärkung an Bord. Riggs kommt nicht mit Mirandas Tod zurecht, während Murtaugh und Trish Probleme haben, einmal Zeit für Zweisamkeit zu finden.</desc>
      <rating>
         <value>12</value>
      </rating>
   </programme>
</tv>

So what i wantes is to have the elements title and sub-title merged. And the elements episode-num, category, date, rating - combined as new element sub-title.

What i tried:

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

    <!-- IDENTITY TRANSFORM -->
    <xsl:template match="node()|@*">  
        <xsl:copy> 
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- REWRITE PROGRAMME -->
    
    <xsl:template match="programme"> 
        <xsl:copy>     
            <xsl:copy-of select="@*"/>
            <title><xsl:value-of select="concat(title, ' ', sub-title)" /></title>
            <xsl:apply-templates select="*[name()!='title' and name()!='sub-title']" /> 
        </xsl:copy>       
    </xsl:template>

      <xsl:template match="programme"> 
        <xsl:copy>    
            <xsl:copy-of select="@*"/>
            <sub-title><xsl:value-of select="episode-num, category, date, country" separator=" | "/><xsl:text> | FSK: </xsl:text> <xsl:value-of select="rating/value"/></sub-title>
            <xsl:apply-templates select="*[name()!='episode-num' and name()!='category'and name()!='date' and name()!='country']"/>
        </xsl:copy>      
    </xsl:template>
       
</xsl:stylesheet>

Thats what i get as output:

<tv generator-info-name="Takealug EPG Grabber Ver. 1.1.2 matrix"
    generator-info-url="https://github.com/DeBaschdi/service.takealug.epg-grabber">

<!--  CHANNEL LIST -->

   <channel id="Warner TV Film">
      <display-name lang="ch">Warner TV Film</display-name>
   </channel>
   <channel id="Warner TV Serie HD">
      <display-name lang="de">Warner TV Serie HD</display-name>
   </channel>

   <!--  PROGRAMME LIST -->

   <programme start="20220111114500  0000"
              stop="20220111143500  0000"
              channel="Warner TV Film">
      <sub-title>Adventure / Western / War | 1997 | US | FSK: 16</sub-title>
      <title lang="ch">Der Soldat James Ryan</title>
      <desc lang="ch">(US) 1997 • FSK 16 • IMDb:★★★★☆
        Captain John Miller soll den Soldaten James Ryan finden und lebend in Sicherheit bringen, um seiner Mutter den letzten Sohn zu retten.</desc>
      <rating>
         <value>16</value>
      </rating>
   </programme>
   <programme start="20220112222500  0000"
              stop="20220112231500  0000"
              channel="Warner TV Serie HD">
      <sub-title>S1 E3 | Drama (Serie) | Action | 2016 | FSK: 12</sub-title>
      <title lang="de">Lethal Weapon</title>
      <sub-title lang="de">Mein Plan, dein Plan</sub-title>
      <desc lang="de"> 2016 • S1 E3 • FSK 12
        Riggs und Murtaugh bekommen es mit einem Drogenkartell zu tun. Wie es scheint, ist auch Murtaughs ehemaliger Ausbilder Ned Brower in die Geschichte verwickelt. Als der Fall zu schwierig für sie wird, holt das Duo ihren Kollegen Cruz als Verstärkung an Bord. Riggs kommt nicht mit Mirandas Tod zurecht, während Murtaugh und Trish Probleme haben, einmal Zeit für Zweisamkeit zu finden.</desc>
      <rating>
         <value>12</value>
      </rating>
   </programme>
</tv>

I tried some things (f.e. changed the order of the input) but i am not able to create an xsl where both changes (sub-title -> title AND episode-num,category,date,rating ->sub-title) get implemented. I am not sure what is my fallacy? Hopefully someone could help me, please. Thaaanks in advance :-)

CodePudding user response:

There are many ways this could be done, but here is a solution :

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

    <!-- IDENTITY TRANSFORM -->
    <xsl:template match="node()|@*">  
        <xsl:copy> 
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- Replace title value with concatenation of title and sub-title -->
    <xsl:template match="programme/title"> 
        <xsl:copy>
            <!-- If sub-title exists, concatenate with title. Else output title as-is. -->
            <xsl:choose>
              <xsl:when test="../sub-title">
                <xsl:value-of select="concat(., ' ', ../sub-title)"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="."/>
              </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
        <!-- Insert new sub-title element -->
        <sub-title>
          <xsl:value-of select="concat(../episode-num, ' ', ../category, ' ', ../date, ' ', ../country)"/>
        </sub-title>
    </xsl:template>
    
    <!-- Remove original sub-title element -->
    <xsl:template match="programme/sub-title"/>
       
</xsl:stylesheet>

See it working here : https://xsltfiddle.liberty-development.net/6qjt5Rv

CodePudding user response:

i did this, additionaly to your code for concetanating from title and sub-title: (I had to remove this code:

<!-- Remove original sub-title element -->
<xsl:template match="programme/sub-title"/> 

to get the right output.

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

<!-- Replace title value with concatenation of title and sub-title -->

<xsl:template match="programme/title">
    <xsl:copy>

        <!-- If sub-title exists, concatenate with title. Else output title as-is. -->

        <xsl:choose>
          <xsl:when test="../sub-title">
            <xsl:value-of select="concat(., ': ', ../sub-title)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="."/>
          </xsl:otherwise>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

    <!-- Insert new sub-title element -->

<xsl:template match="programme/sub-title">
    <xsl:copy>
        <xsl:choose>
          <xsl:when test="../episode-num">
            <xsl:value-of select="concat(../episode-num, ' | ', ../category, ' | ', ../date, ' | ', ../country)"/>
          </xsl:when>
         <xsl:otherwise>
             <xsl:value-of select="concat(../category, ' | ', ../date, ' | ', ../country)"/>
         </xsl:otherwise>
        </xsl:choose>         
    </xsl:copy>
</xsl:template>
  •  Tags:  
  • Related