Willb
Willb

Reputation: 185

XSLT merging and matching values

I'm have a project that seems to have moved someway out of my comfort zone and requires some (advanced?) XSL processing.

I have the following two example XML documents:

Doc1

<instance>
    <InfBy1>Dr Phibes</InfBy1>
    <InfBy2>Dr X</InfBy2>
    <InfBy3>Dr Chivago</InfBy3>
</instance>

Doc2

KB_XMod_Modules>
    <Physician>Dr Phibes</Physician>
    <XModID>60</XModID>
</KB_XMod_Modules>
<KB_XMod_Modules>
    <Physician>Dr X</Physician>
    <XModID>61</XModID>
</KB_XMod_Modules>
<KB_XMod_Modules>
    <Physician>Dr Chivago</Physician>
    <XModID>62</XModID>
</KB_XMod_Modules>

I have to grab the XModID value from Doc2 and match it with the associated name (value) in Doc1. One extra complication however is that this is creating records to load into a database so in my scenario Dr Phibes is within <InfBy1> but in another record he may be in say <InfBy3>. Anyway, the desired output would be:

<InfBy1>
    <items>
        <item>
            <label>Dr Phibes</label>
            <value>60</value>
        </item>
    </items>
</InfBy1>
<InfBy2>
    <items>
        <item>
            <label>Dr X</label>
            <value>61</value>
        </item>
    </items>
</InfBy2>
<InfBy3>
    <items>
        <item>
            <label>Dr Chivago</label>
            <value>62</value>
        </item>
    </items>
</InfBy3>

Any ideas really appreciated...

Thanks,

Will

Upvotes: 2

Views: 201

Answers (1)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243609

This transformation:

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

 <xsl:key name="kPhysByName" match="KB_XMod_Modules"
          use="Physician"/>

 <my:doc2>
    <KB_XMod_Modules>
        <Physician>Dr Phibes</Physician>
        <XModID>60</XModID>
    </KB_XMod_Modules>
    <KB_XMod_Modules>
        <Physician>Dr X</Physician>
        <XModID>61</XModID>
    </KB_XMod_Modules>
    <KB_XMod_Modules>
        <Physician>Dr Chivago</Physician>
        <XModID>62</XModID>
    </KB_XMod_Modules>
 </my:doc2>

 <xsl:template match="/">
  <result>
   <xsl:apply-templates/>
  </result>
 </xsl:template>

 <xsl:template match="/*/*[starts-with(name(), 'InfBy')]">
  <xsl:variable name="vCur" select="."/>
  <xsl:for-each select="document('')">
   <xsl:variable name="vMod" select="key('kPhysByName', $vCur)"/>
   <xsl:copy>
    <items>
     <item>
      <label><xsl:value-of select="$vMod/Physician"/></label>
      <value><xsl:value-of select="$vMod/XModID"/></value>
     </item>
    </items>
   </xsl:copy>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

when applied on the first of the provided XML documents (it contains the second embedded -- just for convenience):

<instance>
    <InfBy1>Dr Phibes</InfBy1>
    <InfBy2>Dr X</InfBy2>
    <InfBy3>Dr Chivago</InfBy3>
</instance>

produces the wanted, correct result:

<result xmlns:my="my:my">
    <items>
        <item>
            <label>Dr Phibes</label>
            <value>60</value>
        </item>
    </items>
    <items>
        <item>
            <label>Dr X</label>
            <value>61</value>
        </item>
    </items>
    <items>
        <item>
            <label>Dr Chivago</label>
            <value>62</value>
        </item>
    </items>
</result>

Explanation:

This transformation is pretty straight-forward. We are using keys for convenience and we are embedding the second document into the XSLT stylesheet for the same reason. In a practical application the second document will be stand-alone and the only change required (except removing it from the stylesheet) will be to replace:

  <xsl:for-each select="document('')">

with:

  <xsl:for-each select="document('someURL')">

Upvotes: 1

Related Questions