user3711142
user3711142

Reputation: 63

XSLT: for_each on two lists

I got following source and I want to get these pairs

list/desc id=1 and rec/val id=1,
list/desc id=2 and rec/val id=2,
list/desc id=3 and rec/val id=3

This is my XML:

<?xml version="1.0" encoding="UTF-8"?>
<xxx>
    <yyy>
        <list>
            <desc id="1" name="Name1"/>
            <desc id="2" name="Name2"/>
            <desc id="3" name="Name3"/>
        </list>
        <rec>
            <val id="1">Value1</val>
            <val id="2"/>
            <val id="3">IValue3</val>
        </rec>
    </yyy>
</pxxx>

I tried for_each on list/desc, but that doesn't help.
Has someone an idea or a hint?

Upvotes: 0

Views: 622

Answers (2)

zx485
zx485

Reputation: 29022

An XSLT-1.0 solution would be

<xsl:template match="/xxx/yyy">  
    <simpletable>
        <sthead>
            <stentry>Name</stentry>
            <stentry>Value</stentry>
        </sthead>
        <xsl:for-each select="list/desc[@id]">
            <strow>
                <stentry><xsl:value-of select="@name" /></stentry>
                <stentry><xsl:value-of select="../../rec/val[@id=current()/@id]/text()" /></stentry>
            </strow>
        </xsl:for-each>
    </simpletable>
</xsl:template>

Output is:

<simpletable>
    <sthead>
        <stentry>Name</stentry>
        <stentry>Value</stentry>
    </sthead>
    <strow>
        <stentry>Name1</stentry>
        <stentry>Value1</stentry>
    </strow>
    <strow>
        <stentry>Name2</stentry>
        <stentry/>
    </strow>
    <strow>
        <stentry>Name3</stentry>
        <stentry>IValue3</stentry>
    </strow>
</simpletable>

Upvotes: 2

Martin Honnen
Martin Honnen

Reputation: 167471

One way would be to use the XSLT 3 xsl:merge instruction

  <xsl:template match="yyy">
      <xsl:merge>
          <xsl:merge-source select="list/desc">
              <xsl:merge-key select="@id"/>
          </xsl:merge-source>
          <xsl:merge-source select="rec/val">
              <xsl:merge-key select="@id"/>
          </xsl:merge-source>
          <xsl:merge-action>
              <strow>
                  <stentry>{current-merge-group()[1]/@name}</stentry>
                  <stentry>{current-merge-group()[2]}</stentry>
              </strow>
          </xsl:merge-action>
      </xsl:merge>
  </xsl:template>

See https://xsltfiddle.liberty-development.net/eiZQaEU which transforms

<xxx>
    <yyy>
        <list>
            <desc id="1" name="Name1"/>
            <desc id="2" name="Name2"/>
            <desc id="3" name="Name3"/>
        </list>
        <rec>
            <val id="1">Value1</val>
            <val id="2"/>
            <val id="3">IValue3</val>
        </rec>
    </yyy>
</xxx>

into

<strow>
   <stentry>Name1</stentry>
   <stentry>Value1</stentry>
</strow>
<strow>
   <stentry>Name2</stentry>
   <stentry/>
</strow>
<strow>
   <stentry>Name3</stentry>
   <stentry>IValue3</stentry>
</strow>

Full minimal sample is

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    expand-text="yes"
    version="3.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="yyy">
      <xsl:merge>
          <xsl:merge-source select="list/desc">
              <xsl:merge-key select="@id"/>
          </xsl:merge-source>
          <xsl:merge-source select="rec/val">
              <xsl:merge-key select="@id"/>
          </xsl:merge-source>
          <xsl:merge-action>
              <strow>
                  <stentry>{current-merge-group()[1]/@name}</stentry>
                  <stentry>{current-merge-group()[2]}</stentry>
              </strow>
          </xsl:merge-action>
      </xsl:merge>
  </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions