[xsl] Re: filtering problem

Subject: [xsl] Re: filtering problem
From: Adrian Herscu <adrian.herscu@xxxxxxxxx>
Date: Sun, 20 Jun 2010 14:58:20 +0300
Thanks for your help, Michael.
It worked :)

I never used such a generic pattern for XML processing and it takes me time to "swallow" it.

I have another problem -- the input now is a test-case comprising of two procedures:

    <case name="CaseA">
      <procedure name="RunSomething">
        <command src="10" />
        <command src="11" />
        <command src="12" />
        <command src="13" />
        <call name="DoFoo">
          <command src="20" />
          <command src="21" />
          <command src="22" />
          <call name="MakeFoo">
            <command src="30" />
            <command src="31" failed="true()" />
            <command src="32" />
          </call>
          <command src="24" />
          <command src="25" failed="true()" />
          <call name="WriteFoo">
            <command src="40" />
            <command src="41" failed="true()" />
            <command src="42" />
          </call>
          <command src="26" />
        </call>
      </procedure>
      <procedure name="RunSomethingElse">
         <command src="100" failed="true()" />
      </procedure>
    </case>

The XSL:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; xmlns:xalan="http://xml.apache.org/xalan";
exclude-result-prefixes="xalan">


  <xsl:output method="xml" indent="yes" encoding="UTF-8"
    media-type="text/xml" xalan:indent-amount="2" />

<xsl:strip-space elements="*" />

<xsl:variable name="firstFailure" select="(//command[@failed=true()])[1]" />
<xsl:variable name="pathToFirstFailure"
select="xalan:nodeset($firstFailure)/ancestor-or-self::*" />
<xsl:variable name="idOfFirstFailure" select="generate-id($firstFailure)" />


  <xsl:template
    match="command[@failed=true() and generate-id(.)=$idOfFirstFailure]">
    <failing-command src="{@src}" />
  </xsl:template>

<xsl:template
match="*[xalan:intersection(node(), xalan:nodeset($pathToFirstFailure))]">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>


<xsl:template match="*" />

</xsl:stylesheet>

The output:
    <case name="CaseA">
      <procedure name="RunSomething">
        <call name="DoFoo">
          <call name="MakeFoo">
            <failing-command src="31" />
          </call>
        </call>
      </procedure>
    </case>

The required output should be:
    <case name="CaseA">
      <procedure name="RunSomething">
        <call name="DoFoo">
          <call name="MakeFoo">
            <failing-command src="31" />
          </call>
        </call>
      </procedure>
      <procedure name="RunSomething">
        <failing-command src="100" />
      </procedure>
    </case>



It seems that another level of filtering is required, but currently do not see how to construct it.

Bast regards and thanks for your help again,
Adrian.

On 20/06/2010 01:24, Michael Kay wrote:
On 19/06/2010 19:12, Adrian Herscu wrote:
<xsl:template match="command[@failed=true()]">

You need to make sure this template only fires for the first command with @failed=true. For example

<xsl:template
match="command[@failed=true()][generate-id(.)=generate-id(@firstFailure)]">

But why are you using XSLT 1.0 with vendor extensions? If you can use
Xalan, then you are almost certainly in an environment where you could
use XSLT 2.0.

Michael Kay
Saxonica

Current Thread