Sojimanatsu
Sojimanatsu

Reputation: 601

How to match template in another template recursively in XSLT 2.0

I have been facing with an issue for few days;

The problem is; I can't match with values inside the template from another template recursively.

Lets assume that we have an example: ...

<book>
   <title>Alice in Wonderland</title>
   <owner>LEWIS CARROLL</owner>
   <numberID>1234</numberID>
</book>

...

This code block has many other siblings and parent nodes as well.

 <Response>
    <ID>1234</ID>
    <name>Jose</name>
    <feedback id="1">It is a good book</feedback>
 <Response>

What i want is , get the feedback value from and write it to under book after the such as:

 <book>
   <title>Alice in Wonderland</title>
   <owner>LEWIS CARROLL</owner>
   <numberID>1234</numberID>
   <feedback>It is a good book</feedback>
 </book>
 ...."for some other nodes other feedbacks" etc

in XSLT i try:

<xsl:template match="book">
   <xsl:param name="bookID" select="numberID"/>
   <xsl:param name=responseID" select="ancestor::*/Response/ID"/>
   <xsl:apply-templates/>
     <xsl:choose>
      <xsl:when test="$bookID=$numberID">
        <xsl:if test="//Response/feedback[@feedbackID="1"]>
            <feedback>
                 <xsl:copy-of select="//Response/feedback">
            <feedback>
        </xsl:if>
      </xsl:when>
     <xsl:choose>

So, please remember the structure is re-created with basic examples. The problem here the output of function are the all elements of node. I want the algorithm to put values recursively into corresponding nodes. but i dont know how to call the other template inside the current one with recursively. I hope that i managed to describe the problem well.

Upvotes: 0

Views: 80

Answers (2)

Daniel Haley
Daniel Haley

Reputation: 52888

Another option is to create an xsl:key that matches feedback and uses the ID from the parent Response.

That will allow you to reference the key using numberID from book.

Example...

XML Input

<doc>
    <books>
        <book>
            <title>Alice in Wonderland</title>
            <owner>LEWIS CARROLL</owner>
            <numberID>1234</numberID>
        </book>
    </books>
    <responses>
        <Response>
            <ID>1234</ID>
            <name>Jose</name>
            <feedback id="1">It is a good book</feedback>
        </Response>
    </responses>
</doc>

XSLT 2.0 (Also works as XSLT 1.0)

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

  <xsl:key name="feedback" match="Response/feedback" use="../ID"/>

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

  <xsl:template match="book">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()|key('feedback',numberID)"/>      
    </xsl:copy>
  </xsl:template>

  <!--Optional: 
  Remove responses element and remove id attribute from feedback element.-->
  <xsl:template match="responses|feedback/@id"/>

</xsl:stylesheet>

Output

<doc>
   <books>
      <book>
         <title>Alice in Wonderland</title>
         <owner>LEWIS CARROLL</owner>
         <numberID>1234</numberID>
         <feedback>It is a good book</feedback>
      </book>
   </books>
</doc>

Working fiddle: http://xsltfiddle.liberty-development.net/pPgCcoz

Upvotes: 1

zx485
zx485

Reputation: 29052

I used these XML as a starting point:

<book>
    <title>Alice in Wonderland</title>
    <owner>LEWIS CARROLL</owner>
    <numberID>1234</numberID>
</book>

... and ...

<Response>
    <ID>1234</ID>
    <name>Jose</name>
    <feedback id="1">It is a good book</feedback>
</Response>

I tried to change your XSLT as little as possible, because the whole structure was not obvious for me. This is the result for which XSLT-1.0 suffices.

XSLT-1.0:

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

<xsl:template match="book">
    <xsl:param name="bookID"   select="numberID"/>
    <xsl:param name="response" select="//Response[ID = $bookID]"/>
    <xsl:copy>
        <xsl:apply-templates />
        <xsl:choose>
            <xsl:when test="$response">                              <!-- if Response with bookID exists... -->
                <xsl:if test="$response/feedback[@id='1']">          <!-- if feedback with id 1 exists... -->
                    <feedback>
                        <xsl:value-of select="$response/feedback" /> <!-- copy only the value and not the whole content -->
                    </feedback>
                </xsl:if>
            </xsl:when>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

Output:

<book>
    <title>Alice in Wonderland</title>
    <owner>LEWIS CARROLL</owner>
    <numberID>1234</numberID>
    <feedback>It is a good book</feedback>
</book>
<Response>
    <ID>1234</ID>
    <name>Jose</name>
    <feedback id="1">It is a good book</feedback>
</Response>

Upvotes: 0

Related Questions