0

So I need to add 4 attributes to the root element (<weather>) of an XML output I am creating using XSLT. The 4 elements are the details of the weather station the data is obtained from. Which is contained within the stations.xml file and has a structure as follows:

<stations>
   <station>
       <site>81123</site>
       <name>Bendigo Airport</name>
       <latitude>36.74</latitude>
       <longitude>144.33</longitude>
       <state>Vic</state>
   </station>
   <station>
       <site>81124</site>
       <name>Yarrawonga</name>
       <latitude>36.03</latitude>
       <longitude>146.03</longitude>
       <state>Vic</state>
   </station>
</stations>

An XPath tester tells me that the following would be the correct predicate to obtain the required station node.

./stations/station[site=81123]

I've tried to do it by matching but I think I've lost my way here. If anyone can offer some assistance that would be great. The code I have so far is below:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>

<!-- select the <measurement> elements of all the various input files -->
<xsl:variable name="maxTemp" select="document('Max_temp.xml')/*" />
<xsl:variable name="rainfall" select="document('Rainfall.xml')/*" />
<xsl:variable name="solar" select="document('Solar.xml')/*" />
<xsl:variable name="minTemp" select="document('Min_temp.xml')/*" />
<xsl:variable name="stations" select="document('station.xml')/*" />

<!-- index <measurement> elements by their station and date -->
<xsl:key name="kMeasurement" match="measurement"
    use="concat(Day, '/', Month, '/', Year)"
/>

<xsl:template match="/">
    <weather>
        <xsl:apply-templates select="weather" />
        <xsl:apply-templates select="$maxTemp/measurement" />
    </weather>
</xsl:template>

<xsl:template match="weather">
    <xsl:attribute name="stationID"><xsl:value-of select="$stations/station[site=81123]/site" /></xsl:attribute>
    <xsl:attribute name="stationName"><xsl:value-of select="$stations/station[site=81123]/name" /></xsl:attribute>
    <xsl:attribute name="latitude"><xsl:value-of select="$stations/station[site=81123]/latitude" /></xsl:attribute>
    <xsl:attribute name="longitude"><xsl:value-of select="$stations/station[site=81123]/longitude" /></xsl:attribute>
</xsl:template>

<xsl:template match="measurement">
    <xsl:variable name="currentKey" select="concat(Day, '/', Month, '/', Year)" />

    <measurement>
        <Date><xsl:value-of select="concat(Day, '/', Month, '/', Year)" /></Date>

        <!-- since we are handling maxTemp measurements here, we can output that directly -->
        <MaxTemp><xsl:value-of select="MaxTemp"/></MaxTemp>

        <!-- to access the others we need a context switch and a key lookup -->
        <xsl:for-each select="$rainfall">
            <Rainfall><xsl:value-of select="key('kMeasurement', $currentKey)/Volume" /></Rainfall>
        </xsl:for-each>
        <xsl:for-each select="$solar">
            <Solar><xsl:value-of select="key('kMeasurement', $currentKey)/dailySolarExposure" /></Solar>
        </xsl:for-each>
        <xsl:for-each select="$minTemp">
            <MinTemp><xsl:value-of select="key('kMeasurement', $currentKey)/minTemp" /></MinTemp>
        </xsl:for-each>
    </measurement>
</xsl:template>

1 Answer 1

1

To minimize the example to the problem at hand, the following stylesheet:

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:variable name="stations" select="document('station.xml')/*" />

<xsl:template match="/">
    <weather>
        <xsl:variable name="station" select="$stations/station[site=81123]" />
        <xsl:attribute name="stationID"><xsl:value-of select="$station/site" /></xsl:attribute>
        <xsl:attribute name="stationName"><xsl:value-of select="$station/name" /></xsl:attribute>
        <xsl:attribute name="latitude"><xsl:value-of select="$station/latitude" /></xsl:attribute>
        <xsl:attribute name="longitude"><xsl:value-of select="$station/longitude" /></xsl:attribute>

        <!-- create content here -->

    </weather>
</xsl:template>

will return:

<?xml version="1.0" encoding="UTF-8"?>
<weather stationID="81123" stationName="Bendigo Airport" latitude="36.74" longitude="144.33"/>

provided it's run against a valid XML input and that the document named station.xml is in the same directory where the stylesheet is located.


If you prefer, you can shorten the above code to:

<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:variable name="stations" select="document('station.xml')/*" />

<xsl:template match="/">
    <xsl:variable name="station" select="$stations/station[site=81123]" />
    <weather stationID="{$station/site}" stationName="{$station/name}" latitude="{$station/latitude}" longitude="{$station/longitude}">

        <!-- create content here -->

    </weather>
</xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

4 Comments

Doesn't seem to work. The data inputs are returning nulls by the look of things.
@RoryPerry I am afraid I don't understand your description of the problem. Make sure you are running this against some valid XML input, and that the station.xml document is in the same directory where the stylesheet is located.
XML Files are all valid. All in the same directory. Output is: <weather stationID="" stationName="" latitude="" longitude="">
Nevermind, I attribute all of this to a rather simple spelling mistake. Should of been stations.xml My apologies if I caused any confusion!

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.