[xsl] Re: XML criterias

Subject: [xsl] Re: XML criterias
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Wed, 3 Jul 2002 08:34:56 -0700 (PDT)
"Chen, Gin" <Gin_Chen at tvratings dot com>  wrote:

> 
> Hi all,
> 	I have an XML document that I need to parse out certain information.
> The information that I'm looking for is in a separate XML generated
> with my
> XSL.
> So an example would be (simplified):
> //in my xml
> <?xml version="1.0" encoding="UTF-8"?>
> <?xml-stylesheet type="text/xsl" href="C:\NAlert\test.xsl"?>
> <datarows>
> 	<rowset id="100" value="100" blah="A"/>
> 	<rowset id="200" value="200" blah="B"/>
> 	<rowset id="300" value="100" blah="C"/>
> </datarows>
> 
> //inside my xsl
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="1.0"
> 	xmlns:xsl="http://www.w3.org/1999/XSL/Transform";;
> 	xmlns:fo="http://www.w3.org/1999/XSL/Format";;
> 	xmlns:c="http://tempuri/criteria";;>
> 
> <xsl:output method="html"/>
> 
> <xsl:variable name="para"
> select="document('')/*/c:criteria/c:parameter"/>
> 
> <xsl:template match="//datarows/rowset">
> 	<xsl:copy-of select="@*[name()=$para/@name and
> .=$para/c:value]/parent::*"/>
> </xsl:template>
> 
> <c:criteria>
> 	<c:parameter name="id">
> 		<c:value>100</c:value>
> 		<c:value>200</c:value>
> 	</c:parameter>
> 	<c:parameter name="value">
> 		<c:value>100</c:value>
> 	</c:parameter>
> </c:criteria>
> 
> </xsl:stylesheet>
> 
> so i'm basically saying that i want to get all datarows/rowsets that
> have
> ids of either 100 or 200 AND value of 100
> the problem is that I'm getting back all rows because its returning
> true if
> any parameter name/value matches.
> I dont want to hardcode all the parameter names in to the select
> because
> there could be alot of attributes to check.
> Is there a better way to do this but still keeping it generic?
> Thanks,
> -Tim


Hi Tim,

As Mike already proposed, it is possible to produce a recursive
solution to your problem. For problems like this I'd use the FXSL
library functions allTrueP() or just foldl().

However, here's a *non-recursive* solution:

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:cr="some:cr" exclude-result-prefixes="cr"
 >
 
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <cr:criteria>
    <parameter name="id">
      <value>100</value>
      <value>200</value>
    </parameter>
    <parameter name="value">
      <value>100</value>
    </parameter>
  </cr:criteria>
  
  <xsl:variable name="vCriteria" 
       select="document('')/*/cr:*"/>
  
  <xsl:variable name="vNumCriteria" 
                select="count($vCriteria/parameter)"/>
  
  <xsl:template match="rowset">
    <xsl:variable name="vCurrent" select="."/>
    
    <xsl:variable name="vTestResults">
      <xsl:for-each select="$vCriteria/parameter">
       <xsl:if test="$vCurrent[@*[name() 
                                 = current()/@name
                                  ]
                               ]        
                                /@value
                     =
                      current()/value">1</xsl:if>
      </xsl:for-each>
    </xsl:variable>
    
    <xsl:if test="string-length($vTestResults) = $vNumCriteria">
      <xsl:copy-of select="."/>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

The idea is to accumulate the successful results of each check into a
string and then to verify whether all checks were successful.

When this transformation is applied on your source xml file:

<datarows>
	<rowset id="100" value="100" blah="A"/>
	<rowset id="200" value="200" blah="B"/>
	<rowset id="300" value="100" blah="C"/>
</datarows>

The result is exactly as required:

<rowset id="100" value="100" blah="A" />
<rowset id="300" value="100" blah="C" />


Hope this helped.

Cheers,
Dimitre Novatchev.


__________________________________________________
Do You Yahoo!?
Sign up for SBC Yahoo! Dial - First Month Free
http://sbc.yahoo.com

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread