Home > OS >  how to match the attribute value of one element with another element, and then make the sum of two a
how to match the attribute value of one element with another element, and then make the sum of two a

Time:07-22

Im very new with XSLT, and now I need to match the value of an attribute of one element in another element, and when it matches, create an attribute with the result of the sum of another attribute of each of these two elements into a single one. Maybe my question is not very clear but the example will explain it better.

I have this XML

<?xml version="1.0" encoding="UTF-8"?>
<puzzle>    
    <BLOCKS>
        <BLOCK X="12" name="BL_01"></BLOCK>
        <BLOCK X="12" name="BL_02"></BLOCK>
        <BLOCK X="12" name="BL_03"></BLOCK>
    </BLOCKS>
    <CONNEXIONS>
        <CONNEXION>
            <SOURCE name="BL_01" id="4"></SOURCE>
        </CONNEXION>
        <CONNEXION>
            <SOURCE name="BL_03" id="1"></SOURCE>
        </CONNEXION>
        <CONNEXION>
            <SOURCE name="BL_02" id="8"> </SOURCE>
        </CONNEXION>
    </CONNEXIONS>
</puzzle>

And now for every element SOURCE, I need to match that name with a element BLOCK, and when it find his match, sum the values of the attributes X and id into a new attribute.

<program>
        <lSource>
            <space pointX="16" ></space>
        </lSource>
        <lSource>
            <space pointX="13" ></space>
        </lSource>
        <lSource>
            <space pointX="20" ></space>
        </lSource>
</program>

Im trying this XSLT, but it does not work (I know the XPATH is not good, that is why I need help)

xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ex="http://exslt.org/dates-and-times" exclude-result-prefixes="ex">
    <xsl:output version="1.0" encoding="UTF-8" standalone="yes" indent="yes" method="html"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="/">
        <program>
        <xsl:for-each select="puzzle/CONNEXIONS/CONNEXION">
                <lSource>
                    <space>
                    <xsl:for-each select="puzzle/CONNEXIONS/CONNEXION/SOURCE">
                    <xsl:if test="CONNEXION/SOURCE/@name] != BLOCK/@name]">
                    <xsl:attribute name="PointX">
                    <xsl:value-of select="puzzle/BLOCKS/BLOCK/@X puzzle/CONNEXIONS/CONNEXION/SOURCE/@id"/>
                    </xsl:attribute>                      
                    </xsl:for-each>
                    </space>
                </lSource>
        </program>
    </xsl:template>
 </xsl:stylesheet>

Any help would be great!

CodePudding user response:

As I said in the comments, it is best to use a key to resolve cross-references:

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:key name="block" match="BLOCK" use="@name" />

<xsl:template match="/puzzle">
    <program>
        <xsl:for-each select="CONNEXIONS/CONNEXION">
            <lSource>
                <space pointX="{key('block', SOURCE/@name)/@X   SOURCE/@id}"/>
            </lSource>
        </xsl:for-each>
    </program>
</xsl:template>

</xsl:stylesheet>

Note that this assumes there can be at most one matching BLOCK for each CONNEXION. If there can be more, use:

                <space pointX="{sum(key('block', SOURCE/@name)/@X)   SOURCE/@id}"/> 

You should also learn about attribute value templates.

  • Related