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?

3
  • Your XPath is invalid. Please use code samples that would actually run. Commented May 28, 2018 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. Commented May 28, 2018 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. Commented May 29, 2018 at 6:31

1 Answer 1

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?

Sign up to request clarification or add additional context in comments.

2 Comments

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.
Ah, of course, the <xsl:copy-of> was not intentional. Also see the update about using separate templates.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.