Take the 2-minute tour ×

I've created an XSLT using an identity template and several templates that match to a potential XPath in the source. However, the matching paths do not always exist. Is there a way to "insert" the path before the matching template applies? Since I know XSLT does not execute procedurally, I wasn't sure how to do this. Examples below.

Let's say this is the XSLT:


<xsl:template match='pathA'>
   do stuff

<xsl:template match='pathB'>
  do something

<xsl:template match='pathC'>
   do other stuff

And let's say this in the input:

        <pathA>I have Data!</pathA>
        <pathC>We skipped B!</pathC>

Is there a way to "create" pathB so that the template that matches the XPath can execute?

Thanks again for any assistance!

share|improve this question
I don't think it's possible without doing two passes with XSLT. You can probably achieve what you're looking for, though: for example, you could process a pathC element without a preceding pathB sibling differently than a pathC element with one by adding a template match like this: <xsl:template match="pathC[not(preceding-sibling::pathB)]"> ... </xsl:template>. –  Eero Helenius Feb 26 '13 at 8:31
That's a good point, I may try that. My only concern is scale. What happens when you have all the way to path AY? Do you then create a different template for all the different permutations? –  J R Feb 26 '13 at 15:20
Possibly. It depends on what you want to happen when you have all the way to pathY. Maybe you want to match all children of <Child> that don't have a preceding pathB sibling? (<xsl:template match="Child/*[not(preceding-sibling::pathB)]">) I'd need to know a bit more about exactly what you want to achieve to give more concrete suggestions. Adding a sample of your expected output into your question would help. –  Eero Helenius Feb 26 '13 at 16:52
that's a good suggestion also. Essentially, "<Child>" contains response data from an inquiry. I have the schema for all the potential values, but only the items that have values in the table will be populated in the xml response. What I'm trying to do is "update" the data by using match templates. The only problem is when I need to add a value, so the xpath doesn't exists to match to. You can see the original question in this post: stackoverflow.com/questions/15079437/… –  J R Mar 1 '13 at 4:18
add comment

1 Answer

Good one. How about...

<xsl:template name="pathB">
    <xsl:param name="nodes"/>
    do something 

<xsl:template match="Child">
        <xsl:apply-templates select="@* | pathA[not(../pathB)] | pathB/preceding-sibling::node()"/>

   <xsl:call-template name="pathB">
       <!-- pass the set of elements of type "pathB", possibly an empty nodeset -->
       <xsl:with-param name="nodes" select="pathB"/>

        <xsl:apply-templates select="node()[not(self::pathA) and not(../pathB)] | pathB/following-sibling::node()"/>
share|improve this answer
hrmm.. would this template still work if pathB isn't available to reference in the source? I tried with a larger source xml I have and it copied everything, but then when I added the "element" tag to build out pathB, it built it first then only copied the text from the source nodes. –  J R Feb 26 '13 at 15:18
Aha, my bug. Fixing. –  minopret Feb 26 '13 at 15:25
As you see, the intention of my code is no different from the intention of the comment by @EeroHelenius (sorry I'm not good at mentioning people using @ so that may not work). However it may help you to see the additional details that I have included, which in my experience are not in every XSL developer's repertoire. –  minopret Feb 26 '13 at 15:39
add comment

Your Answer


