[xsl] Merging data based on attributes

Subject: [xsl] Merging data based on attributes
From: "Bob Portnell" <simply.bobp@xxxxxxxxx>
Date: Wed, 23 Aug 2006 08:56:44 -0700
It's a perennial problem, and yet after hitting all the faqs and the
archives, I can't see my way clear of this. I tried Muenchian-ness under
XSLT 1.0, and didn't clear it. Now I'm up to XSLT 2.0, and I'm closer but
still not there.

The premise is to transform an SVG file, replacing dummy text in the SVG
with content from an outside file.

Here's the SVG file
=============================================================================
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "
http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd";>
<?xml-stylesheet type="text/xsl" href="newtest.xsl"?>

<svg xmlns="http://www.w3.org/2000/svg"; contentStyleType="text/css"
contentScriptType="text/ecmascript"
   version="1.1" zoomAndPan="magnify" preserveAspectRatio="xMidYMid meet"
   width="100%" height="100%">

<defs/>

   <desc>
       Test Page
   </desc>

<!-- TEXT ELEMENTS -->
   <g font-family="Arial" font-size="24">
       <!-- DOCUMENT TITLE -->
       <text><tspan x="400" y="60" text-anchor="middle">Test
Page</tspan></text>
   </g>

   <g font-family="Arial" font-size="8" text-anchor="middle" id="k1"> <!--
There's the id to match with -->
       <text x="80" y="140">element</text> <!-- This text tag has dummy
content -->
       <text x="80" y="150">phase</text>    <!-- So does this one. -->
   </g>

   <g font-family="Arial" font-size="8" text-anchor="middle" id="k2">
       <text x="80" y="220">element</text>
       <text x="80" y="230">phase</text>
   </g>

   <g font-family="Arial" font-size="8" text-anchor="middle" id="k3">
       <text x="80" y="300">element</text>
       <text x="80" y="310">phase</text>
   </g>

<!-- GRAPHIC ELEMENTS -->

   <g fill="none" stroke="black" stroke-width="2">
       <rect x="40" y="120" width="80" height="50" pointer-events="all"
visibility="visible" />
   </g>

   <g fill="none" stroke="black" stroke-width="2">
       <rect x="40" y="200" width="80" height="50" pointer-events="all"
visibility="visible" />
   </g>

   <g fill="none" stroke="black" stroke-width="2">
       <rect x="40" y="280" width="80" height="50" pointer-events="all"
visibility="visible"/>
   </g>

</svg>


Here's the data file ============================================================================= <?xml version="1.0" encoding="UTF-8"?>

<test>
   <data id="k3">
       <element>Tritium</element>
       <phase>plasma</phase>
   </data>
   <data id="k2">
       <element>Deuterium</element>
       <phase>solid</phase>
   </data>
   <data id="k1">
       <element>Hydrogen</element>
       <phase>gas</phase>
   </data>
</test>

The result file should look just like the input, except for the dummy text
being changed.
=============================================================================
   <g font-family="Arial" font-size="8" text-anchor="middle" id="k1"> <!--
There's the id to match with -->
       <text x="80" y="140">Hydrogen</text> <!-- This text tag has dummy
content -->
       <text x="80" y="150">gas</text>    <!-- So does this one. -->
   </g>

   <g font-family="Arial" font-size="8" text-anchor="middle" id="k2">
       <text x="80" y="220">Deuterium</text>
       <text x="80" y="230">solid</text>
   </g>

   <g font-family="Arial" font-size="8" text-anchor="middle" id="k3">
       <text x="80" y="300">Tritium</text>
       <text x="80" y="310">plasma</text>
   </g>

And here's the transform as I have it so far.
=============================================================================
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
   xmlns:xs="http://www.w3.org/2001/XMLSchema";
   xmlns:fn="http://www.w3.org/2005/02/xpath-functions";
   xmlns:xdt="http://www.w3.org/2005/02/xpath-datatypes";>

<xsl:output method="xml" encoding="utf-8"
   doctype-public="-//W3C//DTD SVG 1.1//EN"
   doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"; />

<!-- copies all nodes/attributes into result tree unchanged -->
<xsl:template match="@*|node()">
   <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>

<xsl:template match="/svg/g">
   <xsl:variable name="srcnode" select="." />
   <xsl:for-each select="document('textsrc.xml')/test/data
                               [every $att in @* satisfies current()/@*
                                   [.=$att and name(.)=name($att)]]">
       <xsl:variable name="elem" select="/element" />  <!-- aliases target
content in TXT file -->
       <xsl:variable name="phaz" select="/phase" />  <!-- aliases target
content in TXT file -->
       <xsl:value-of select='replace($srcnode, "element","$elem")'/>
       <xsl:value-of select='replace($srcnode, "phase","$phaz")'/>
   </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

For a problem which is so easy to describe or envision, I have sure had a
wretched time working up a solution. Pointers to already logged solutions,
or tips on this one directly, would be very welcome. Thanks.

Bob P
simply.bobp@xxxxxxxxx

Current Thread