Willb
Willb

Reputation: 185

XSL match some but not all

I have a solution from an earlier post that was kindly provided by Dimitre Novatchev.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my">
  <xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/>
  <xsl:key name="kPhysByName" match="KB_XMod_Modules" use="Physician"/>
  <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('doc2.xml')">
      <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>

I now need to use additional fields in my source XML and need the existing labels intact but I'm having problems getting this going.

<instance>
  <NewTag>Hello</newTag1>
  <AnotherNewTag>Everyone</AnotherNewTag>
  <InfBy1>Dr Phibes</InfBy1>
  <InfBy2>Dr X</InfBy2>
  <InfBy3>Dr Chivago</InfBy3>
</instance>

It drops the additional labels and outputs

<result xmlns:my="my:my">
  HelloEveryone 
  <items>
    <item>
      <label>Dr Phibes</label>
      <value>60</value>
    </item>
  </items>
  ...

I've been experimenting a lot with

<xsl:otherwise>
  <xsl:copy-of select=".">
  </xsl:copy-of>
</xsl:otherwise>

but being an xsl newbie I can't seem to get this to work. I've a feeling I'm barking up the wrong tree!

Does anyone have any ideas?

Thanks,

Will

Upvotes: 0

Views: 338

Answers (2)

Tomalak
Tomalak

Reputation: 338108

This is a side-effect of <xsl:apply-templates> which tries to find a matching template for every child node it encounters, in conjunction with implied XSLT "default behavior".

In your case, it encounters <NewTag> and <AnotherNewTag>, but there are no templates for these nodes.

The default behavior (the hidden default template) that catches this case copies the text value of the element to the output stream.

The text value of <NewTag> is "Hello", that of <AnotherNewTag> is "Everyone", so you see "HelloEveryone".

If you do not want this, write your own template that catches these nodes:

<xsl:template match="NewTag|AnotherNewTag">
  <xsl:copy-of select="." />
</xsl:template>

Alternatively, write one that catches any unhandled element node:

<!-- empty templates do nothing (matched nodes do not appear in the output) -->
<xsl:template match="*" />

If you want to copy unhandled nodes unchanged but still want to recursively apply templates within them, the identity template (@Alejandro's answer shows it) is the way to go.

Upvotes: 0

user357812
user357812

Reputation:

Your NewTag and AnotherNewTag elements are matched by the Built-in Template Rules. If you want another kind of transformation you need to declare such rules.

need the existing labels intact

Then you are looking for the identity rule

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

Upvotes: 2

Related Questions