3

It is a bit difficult to explain so I speak in XML..

XML-File which I want to transform

<Items>
<Item ID="1" Name="Student">
  <Cell Name=""/>
  <Cell Number=""/>
</Item>
<Item ID="1" Name="Professor">
  <Cell Name=""/>
  <Cell Number=""/>
</Item>

values.xml with all attribute values

<students>
  <count>2</count>
    <student number="1">
      <name>Peter</name>
      <number>1234</number>
    </student>
    <student number="2">
      <name>Stefan</name>
      <number>4567</number>
    </student>
</students>

desired output

    <Items>
        <Item ID="1" Name="Student">
            <Cell Name="Max"/>
            <Cell Number="1234"/>
        </Student>
        <Item ID="2" Name=Student>
            <Cell Name="Stefan"/>
            <Cell Number="4567"/>
        </Professor>
    </Items>

My Idea

    <xsl:variable name="total" select="document('values.xml')"/>

    <!-- Identity Transformation --> ||WORKS FINE||

    <!-- copy students n-times --> ||WORKS FINE||

<!-- set attribute: name --> ||DOESN'T WORK|| 
<xsl:template match="v:Items/Item/Cell[1]">
<xsl:param name="c" select="1"/>
<xsl:param name="values" select="$total/students/student[@number=$c]"/>    
    <xsl:copy>          
        <xsl:attribute name="Name">
                <xsl:copy-of select="$values/name"/>
            </xsl:attribute>                
            <xsl:apply-templates/>
    </xsl:copy>             
    <xsl:if test="$c &lt; $total/students/count">
        <xsl:apply-templates select=".">
            <xsl:with-param name="c" select="$c+1"/>                        
        </xsl:apply-templates>          
    </xsl:if>       
</xsl:template>

I get both attribute values in each element. But I want the first attribute value in the first (Cell-)element , the second attribute value in the second (Cell-)element and so on.

0

1 Answer 1

1

EDIT: A shorter way to achieve this is to count the position in the XML and use that to get the index of the Cell and the student.

<xsl:template match="Items/Item">
    <xsl:variable name="idx"><xsl:number /></xsl:variable>  <!-- index of this 'Item' -->
    <xsl:variable name="values" select="$total/student[@number=$idx]"/> 
    <xsl:copy>          
        <xsl:copy-of select="@*" />                         <!-- copy attributes of this 'Item' -->
        <xsl:apply-templates select="Cell">                 
            <xsl:with-param name="cell" select="$values" /> <!-- pass current 'student' as parameter -->
        </xsl:apply-templates>
    </xsl:copy>             
</xsl:template>

<xsl:template match="Cell">
    <xsl:param name="cell" />
    <xsl:variable name="idx" select="position()" />
    <xsl:variable name="firstAttr" select="name(@*[1])" />  <!-- get the name of the first attribute of this 'Cell' -->
    <xsl:copy>          
        <xsl:attribute name="{$firstAttr}">                 <!-- recreate attribute -->
            <xsl:value-of select="$cell/*[$idx]"/>          <!-- use position() of this 'Cell' as index in the current 'student' -->
        </xsl:attribute>        
    </xsl:copy>             
</xsl:template>

The second template puts the nth child element of the current student into the first attribute of the nth Cell.

If you want to match only the student Cells, you can use an empty template to filter out the 'Professor' Items:

<xsl:template match="Items/Item[@Name='Professor']" />    

Then restrict the first template from above with a predicate:

<xsl:template match="Items/Item[@Name='Student']">
   <xsl:variable name="idx" select="@ID"></xsl:variable>
   ...
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.