0

I'm trying to learn the different possibilities to generalize XSLT templates for the sake of reusing them at different places. So far, I have two cases where I do not know how to proceed.

Case 1 - source XML might contain nodes Foo1, Foo2, ..., Foo10 (but doesn't have to contain any or all of them). For example,

<Foo1>some value</Foo1>
<Foo3>some other value</Foo3>

I need to create nodes as follows:

<Bar number="1">some value</Bar>
<Bar number="3">some other value</Bar>

My XSLT currently is very simple:

<xsl:if test="Foo1 != ''">
  <xsl:element name="Bar">
    <xsl:attribute name="number">1</xsl:attribute>
    <xsl:value-of select="Foo1"/>
  </xsl:element>
</xsl:if>

But I obviously need 10 of these code blocks. How can I generalize this?

Case 2 - In the source XML, I have a couple of nodes of basically the same structure:

<Foo>
  <item>
    <Start>2015-06-01</Start>
    <End>9999-12-31</End>
    <Foo>00000008</Foo>
  </item> <!-- 0..n items -->
</Foo>

The nodes differ in the name Foo, but the rest stays the same. The structure I need to build looks like this:

<Bars>
  <Bar From="2015-06-01" To="9999-12-31">
    <Value>00000008</Value>
  </Bar>
</Bars>

here's my XSLT attempt, but once again, I need many templates which are very similar to each other:

<xsl:element name="Bars>
  <apply-templates select="Foo"/>
</xsl:element>

...

<xsl:template match="Foo/item">
  <xsl:element name="Bar">
    <xsl:attribute name="From">
      <xsl:call-template name="convertDate">
        <xsl:with-param name="theDate" select="Start"/>
      </xsl:call-template>
    </xsl:attribute>
    <xsl:attribute name="To">
      <xsl:call-template name="convertDate">
        <xsl:with-param name="theDate" select="End"/>
      </xsl:call-template>
    </xsl:attribute>
    <xsl:element name="Value">
      <xsl:value-of select="Foo"/>
    </xsl:element>
  </xsl:element>
</xsl:template>

And once more, I have several of the templates, all of which look very similar (i.e., they only differ in the names of the Foo, Bar, and Value elements). Any chance to generalize this, i.e. to provide a single template which can handle all these cases?

csoltenborn
  • 1,127
  • 1
  • 12
  • 22
  • For 1) you should be able to generate the names from a sequence and for 2) you should be able to retrieve the value by xpath "last-child-of-item" (pseudo-xpath). I don't have time for a full answer right now but I'll check back later. – Filburt Jun 28 '16 at 12:10
  • @Filburt Could you maybe elaborate a bit on your suggestion for 2)? I'm still a bit lost on that one... Thanks in advance. – csoltenborn Jun 29 '16 at 11:28

1 Answers1

2

You can use

<xsl:template match="*[starts-with(local-name(), 'Foo')]">
  <Bar number="{translate(local-name(), translate(local-name(), '1234567890', ''), '')}">
    <xsl:apply-templates/>
  </Bar>
</xsl:template>

for the first sample.

To convert

  <item>
    <Start>2015-06-01</Start>
    <End>9999-12-31</End>
    <Foo>00000008</Foo>
  </item>

to

  <Bar From="2015-06-01" To="9999-12-31">
    <Value>00000008</Value>
  </Bar>

you can use

<xsl:template match="item">
  <Bar From="{Start}" To="{End}">
    <xsl:value-of select="Foo"/>
  </Bar>
</xsl:template>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • 1
    I think the second one doesn't address the OP issue: `Foo` is an arbitrary element as I understood the problem, so `` will not work. – Filburt Jun 28 '16 at 12:38
  • Admittedly I am not sure on the second problem, whether the statement "The nodes differ in the name Foo" relates to the `Foo` container of the `item` elements or to the `Foo` child. – Martin Honnen Jun 28 '16 at 12:45
  • Thanks for the quick answers! I have already implemented the first solution you provided, just had to replace the `` with `` (probably because I have overridden the according built-in template). – csoltenborn Jun 28 '16 at 15:37
  • For your second solution, @Filburt is right (sorry for not being precise enough): both `Foo` elements are arbitrary (but always have the same name as far as I can see). Thus, `Foo` referred to both the container *and* the child element. – csoltenborn Jun 28 '16 at 15:40