0

I am trying to insert a value from one field, if another field with the same parents has a certain value.

<xsl:if test="s0:PRILoop1/s0:PRI/s0:C509/C50901='AAB'">
                  <UnitPrice>
                    <xsl:value-of select="../C50902"/>
                  </UnitPrice>
                </xsl:if>

If C50901='AAB', then the value in C50902 should be inserted into the UnitPrice. I am assuming after the if element, I need to go back one level, and then down into the sibling element to select it, but no value is being carried over in this case.

Does scope work different with if elements? How can I see where I am in relation to the other elements?

Leth
  • 1,033
  • 3
  • 15
  • 40
  • Your XPath is invalid. Please use code samples that would actually run. – Tomalak May 28 '18 at 12:01
  • When you say "scope" I think you mean "context", or as XPath 2.0 calls it, "focus". An xsl:if instruction does not change the focus. – Michael Kay May 28 '18 at 18:36
  • Yea, that's what I meant. Sorry I got the two terms mixed up. I am mostly using XSLT 1.0 as Biztalk does not yet support XSLT 2.0. – Leth May 29 '18 at 06:31

1 Answers1

2

When you need this path in your <xsl:template> to get to the element you want to check:

s0:PRILoop1/s0:PRI/s0:C509/C50901[.='AAB']

...then you cannot use this path in your <xsl:if> to get to the element you want to insert:

../C50902

That's because the context node in the <xsl:if> still remains at the exact same spot higher up in the tree. You would need a full path to get to it:

s0:PRILoop1/s0:PRI/s0:C509/C50901[.='AAB']/../C50902

Luckily it's much easier and more logical to simply change the context node. You can do so with <xsl:for-each> (even if there is only one node to "iterate"):

<xsl:for-each select="s0:PRILoop1/s0:PRI/s0:C509[C50901='AAB']">
    <!-- ...we are at the <s0:C509> element at this point! -->
    <UnitPrice>
        <xsl:value-of select="C50902"/>
    </UnitPrice>
</xsl:for-each>

This doubles as an <xsl:if>. When s0:PRILoop1/s0:PRI/s0:C509[C50901='AAB'] does not exist, the loop does not run.


More idiomatically you would have a separate template:

<xsl:template match="foo">
    <!-- just output that <s0:C509>, the XSLT engine will decide what to do -->
    <xsl:apply-templates select="s0:PRILoop1/s0:PRI/s0:C509" />
</xsl:template>

<xsl:template match="s0:C509[C50901='AAB']">
    <UnitPrice>
        <xsl:value-of select="C50902"/>
    </UnitPrice>
</xsl:for-each>

<xsl:template match="s0:C509[C50901='SomethingElse']">
    <SomethingElse>
        <xsl:value-of select="SomethingElse"/>
    </SomethingElse>
</xsl:for-each>

<!-- any <s0:C509> we don't have a template for will be suppressed -->
<xsl:template match="s0:C509" />

This makes sense when you have more than one case to look after, the effect is that of a switch statement.


How can I see where I am in relation to the other elements?

The context node generally stays the same. Imagine the chaos when the context node would magically be something else just because you did an <xsl:if test="...">.

There are only very few constructs that change the context, mainly <xsl:for-each>, <xsl:apply-templates> and <xsl:for-each-group>. See List of XSLT instructions/functions that change the context node?

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • 1
    Thanks for a detailed answer! It makes much more sense now. I used value-of instead of copy-of, since it carried over a namespace I didnt need. – Leth May 28 '18 at 12:14
  • Ah, of course, the `` was not intentional. Also see the update about using separate templates. – Tomalak May 28 '18 at 12:18