2
votes

I'm expecting to see hello in the output, but not getting it.

xsl

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

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:if test="//target">
      <xsl:value-of select="@field"/>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

xml

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="callwithparms - Copy.xslt"?>

<xml>
  <partOne>
    <target field="hello"/>
  </partOne>
  <partTwo>
    <number input="2" find="hello" />
    <number input="2" find="world" />
  </partTwo>
</xml>
2

2 Answers

3
votes

Change

  <xsl:value-of select="@field"/>

to

  <xsl:value-of select="//target/@field"/>

(There is no @field attribute on the context node at that point, root; the if statement does not change the context node as your original code seems to be expecting.)

Credit: Thanks to Daniel Haley for correcting original answer saying that the context node was the root element where it really is the root.

1
votes

Why can't you expect this output?

Because your transformation would read like this in plain text:

"Match the root and test if there is a <target> anywhere in the document and if that is the case select the field attribute of the current node"

... which is still /, not <target> as you'd expect.

Your xsl should look like this:

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

    <xsl:output method="text"/>

    <!-- work your way thru the doc with matching templates ... -->
    <xsl:template match="/">
        <!-- ... and simply apply-templates -->
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="xml">
        <!-- ... and more ... -->
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="partOne">
        <!-- ... and more ... -->
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="target">
        <!-- until you reach the desired element you need -->
        <xsl:value-of select="@field"/>
    </xsl:template>

    <!-- creating empty templates for elements you like to ignore -->
    <xsl:template match="partTwo" />

</xsl:stylesheet>

It will make things easier for as complexity starts to rise if you can rely on a series of matching templates instead of trying to for-each or reach for elements far up or down in the document structure.