Home > Software engineering >  How to make xsl using info from two xml files, when attribute values match?
How to make xsl using info from two xml files, when attribute values match?

Time:07-06

I have two xml files, named 1.xml and 2.xml. '1.xml' consists of two elements, aa and bb. 'bb' has three attributes: date, num and class.

'2.xml' has five elements, cc, dd> ee, ff and gg. Two of them got one attribute each: 'dd' (id) and 'ff' (class).

I want to make a xsl that uses the values of the date attribute from '1.xml' to find the id element in '2xml' with the corresponding attribute values.

'1.xml': 
<aa>
<bb date="31.12.2022" num="prs1" ></bb>
<bb date="07.01.2023" num="prs2" ></bb>
</aa>

Here's the other

'2.xml'
<cc>
<dd id="prs1">
    <ee>steak</ee>
    <ff>
        <gg >carrot cake</gg>
        <gg >chocolate cake</gg>
        <gg >cream cake</gg>
    </ff>
</dd>
<dd id="prs2">
    <ee>chicken</ee>        
    <ff>
        <gg >Swiss roll</gg>
        <gg >Napoleon cake</gg>
        <gg >marzipan cake</gg>            
    </ff>
</dd>    
</cc>

This is what I want to get:

    <table>
        <tr>
            <td>31.12.2022</td>
            <td>steak</td>
            <td>cream cake</td>
        </tr>
        <tr>
            <td>07.01.2023</td>
            <td>chicken</td>
            <td>Napoleon cake</td>
        </tr>
    </table>

This is what I've got so far:

<body>
  <table>
     <tr>
        <td>31.12.2022</td>
        <td></td>
     </tr>
     <tr>
        <td>07.01.2023</td>
        <td></td>
     </tr>
  </table>
<xsl:template match="aa">
    <html>
        <body>
            <table>
                <xsl:for-each select="bb">
                <tr>
                    <td><xsl:value-of select="@date"/></td>
                    <td><xsl:variable name="bbnum" select="@num"/>
                    <xsl:variable name="bbid" select="document('2.xml')/cc[@id = current()/dd/@id]/*"/> 
                    <xsl:if test="$bbnum!=$bbid">     
                        <xsl:value-of select="ee"/>
                    </xsl:if> </td>
                    <td></td>
                </tr>
                </xsl:for-each>
            
        
            </table>        
        </body>
    </html>
</xsl:template>

CodePudding user response:

If your processor supports XSLT 2.0 or higher, then you could do:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="k1" match="dd" use="@id" />
<xsl:key name="k2" match="gg" use="@class" />

<xsl:template match="/aa">
    <html>
        <body>
            <table>
                <xsl:for-each select="bb">
                    <xsl:variable name="dd" select="key('k1', @num, document('2.xml'))" />
                    <tr>
                        <td>
                            <xsl:value-of select="@date"/>
                        </td>
                        <td>
                            <xsl:value-of select="$dd/ee"/>
                        </td>
                        <td>
                            <xsl:value-of select="key('k2', @class, $dd)"/>
                        </td>
                    </tr>
                </xsl:for-each>
            </table>        
        </body>
    </html>
</xsl:template>

</xsl:stylesheet>

If you are limited to XSLT 1.0, then it's a little more complicated, but still doable.

CodePudding user response:

It looks like you want to

  • convert every bb from doc1.xml into a tr,
  • put its date attribute into a td,
  • take the bb element's num attribute and look in doc2.xml for a dd with a matching id, and create a second td with the value of the ee child of the dd
  • then use the bb element's class attribute to find an ff/gg descendant of the dd with a matching class attribute, and use its content to create a third td.
<xsl:template match="aa">
    <xsl:variable name="doc2" select="document('2.xml')"/>
    <html>
        <body>
            <table>
                <xsl:for-each select="bb">
                    <xsl:variable name="bb-num" select="@num"/>
                    <xsl:variable name="dd" select="$doc2/cc/dd[@id=$bb-num]"/> 
                    <xsl:variable name="bb-class" select="@class"/>
                    <xsl:variable name="gg" select="$dd/ff/gg[@class=$bb-class]"/> 
                    <tr>
                        <td><xsl:value-of select="@date"/></td>
                        <td><xsl:value-of select="$dd/ee"/></td>
                        <td><xsl:value-of select="$gg"/></td>
                    </tr>
                </xsl:for-each>
            </table>        
        </body>
    </html>
</xsl:template>

  • Related