Reputation: 173
I have two xml files:
Source.xml
<osm>
<count>
<tag k="total" v="1560"/>
</count>
<node>
<tag k="fhrs:id" v="111111"/>
</node>
<node>
<tag k="fhrs:id" v="222222"/>
<tag k="addr:postcode" v="XXX XXX"/>
</node>
<node>
<tag k="fhrs:id" v="333333"/>
<tag k="addr:postcode" v="YYY YYY"/>
</node>
<way>
<tag k="fhrs:id" v="444444"/>
</way>
<way>
<tag k="fhrs:id" v="555555"/>
<tag v="ZZZ ZZZ"/>
</way>
</osm>
Lookup.xml
<FHRSEstablishment>
<EstablishmentCollection>
<EstablishmentDetail>
<FHRSID>111111</FHRSID>
<PostCode>BA1 111</PostCode>
</EstablishmentDetail>
<EstablishmentDetail>
<FHRSID>333333</FHRSID>
<PostCode>BA2 222</PostCode>
</EstablishmentDetail>
<EstablishmentDetail>
<FHRSID>555555</FHRSID>
<PostCode>BA3 333</PostCode>
</EstablishmentDetail>
</EstablishmentCollection>
</FHRSEstablishment>
I wish to compare them using the corresponding @v
value of the k=fhrs:id
attribute in source.xml with the FHRSID
node value in lookup.xml to produce an amended version of source.xml.
When a match is found, the value of the Postcode
node should be copied across to replace the value of the @v
attribute for the tag element with the attribute k="addr:postcode"
.
This is the XSL fille:
<xsl:key name="FHRSID-key" match="FHRSID" use="node()"/>
<xsl:variable name="lookup-doc" select="doc('lookup.xml')"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*/tag[@v and key('FHRSID-key', @v, $lookup-doc)]">
<xsl:copy>
<xsl:attribute name="k">addr:postcode</xsl:attribute>
<xsl:attribute name="v" select="key('FHRSID-key', @v, $lookup-doc)/../PostCode/node()"/>
</xsl:copy>
</xsl:template>
This is the current output
<osm>
<count>
<tag k="total" v="1560"/>
</count>
<node>
<tag k="addr:postcode" v="BA1 111"/>
</node>
<node>
<tag k="fhrs:id" v="222222"/>
<tag k="addr:postcode" v="XXX XXX"/>
</node>
<node>
<tag k="addr:postcode" v="BA2 222"/>
<tag k="addr:postcode" v="YYY YYY"/>
</node>
<way>
<tag k="fhrs:id" v="444444"/>
</way>
<way>
<tag k="addr:postcode" v="BA3 333"/>
<tag k="addr:postcode" v="ZZZ ZZZ"/>
</way>
</osm>
This is the desired ouput:
<osm>
<count>
<tag k="total" v="1560"/>
</count>
<node>
<tag k="fhrs:id" v="111111"/>
<tag k="addr:postcode" v="BA1 111"/>
</node>
<node>
<tag k="fhrs:id" v="222222"/>
<tag k="addr:postcode" v="XXX XXX"/>
</node>
<node>
<tag k="fhrs:id" v="333333"/>
<tag k="addr:postcode" v="BA2 222"/>
</node>
<way>
<tag k="fhrs:id" v="444444"/>
</way>
<way>
<tag k="fhrs:id" v="555555"/>
<tag k="addr:postcode" v="BA3 333"/>
</way>
</osm>
As you can see it's replacing the 'fhrs:id'
element with the copied postcode element, instead of the original k="addr:postcode"
.
Incidental questions:
match="*/tag[@v and key('FHRSID-key', @v, $lookup-doc)]"
Is the first occurrence of @v
actually doing anything?
To me, this match appears to be searching all tag elements. If so, how can it be restricted to look just for those with just the k="addr:postcode"
attribute.
Any other improvements to be recommended, please feel free.
Upvotes: 0
Views: 104
Reputation: 167716
Changing the code to match on the parent
<xsl:key name="FHRSID-key" match="EstablishmentDetail" use="FHRSID"/>
<xsl:variable name="lookup-doc" select="doc('lookup.xml')"/>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[tag[@k = 'fhrs:id' and key('FHRSID-key', @v, $lookup-doc)]]">
<xsl:copy>
<xsl:apply-templates select="@* , node() except tag[@k = 'addr:postcode']"/>
<tag k="addr:postcode" v="{key('FHRSID-key', tag[@k = 'fhrs:id']/@v, $lookup-doc)/PostCode}"/>
</xsl:copy>
</xsl:template>
gives
<osm>
<count>
<tag k="total" v="1560"/>
</count>
<node>
<tag k="fhrs:id" v="111111"/>
<tag k="addr:postcode" v="BA1 111"/>
</node>
<node>
<tag k="fhrs:id" v="222222"/>
<tag k="addr:postcode" v="XXX XXX"/>
</node>
<node>
<tag k="fhrs:id" v="333333"/>
<tag k="addr:postcode" v="BA2 222"/>
</node>
<way>
<tag k="fhrs:id" v="444444"/>
</way>
<way>
<tag k="fhrs:id" v="555555"/>
<tag v="ZZZ ZZZ"/>
<tag k="addr:postcode" v="BA3 333"/>
</way>
</osm>
where the only problem seems to be the <tag v="ZZZ ZZZ"/>
element. I am not sure which are the criteria to copy or not copy existing content, if you only want to keep the tag k="fhrs:id"
then change that last template to
<xsl:template match="*[tag[@k = 'fhrs:id' and key('FHRSID-key', @v, $lookup-doc)]]">
<xsl:copy>
<xsl:apply-templates select="@* , tag[@k = 'fhrs:id']"/>
<tag k="addr:postcode" v="{key('FHRSID-key', tag[@k = 'fhrs:id']/@v, $lookup-doc)/PostCode}"/>
</xsl:copy>
</xsl:template>
Upvotes: 1