Solved

xsl:apply-templates dynamic filter

Posted on 2002-05-07
10
856 Views
Last Modified: 2010-05-18
Hi,

I need to dynamicaly filter the data that would be processed by a template.

The filter query is stored in a diferent nome, and it could be something like

data/row[Produto='Produto 4'].

i have a xsl that does all the tranformation. I need to restrict it to those nodes mathing the previous query

This is the xsl i'm using
<xsl:param name="filter" select="/webGrid/currentinfo/filter"/>
<xsl:value-of select="$filter"/>
<xsl:apply-templates select="$filter">

my problem is that the last line doesn't work.

If i replace the select="$filter" by the query path it works ok. How can i do it using the value stored in a diferent node ?

help please!!

0
Comment
Question by:PedroG
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 3
10 Comments
 
LVL 23

Expert Comment

by:b1xml2
ID: 6995561
the select attribute cannot accept a variable per se but a valid XPath expression.

Post us your XML and XSLT and we will what we can do.

what you could do in your case is the following:

<xsl:apply-templates select="data/row[Produto[. = $filter]]" />

or

<xsl:apply-templates select="data/*[name() = $node and Produto[. = $filter]]" />

or

<xsl:apply-templates select="*[name() = $parent and *[name() = $child and . = $filter]]" />

that's how you can use variables in your XPath statements in that it is a matter comparison and not the actual XPath expression.

Regards,

Brandon Driesen
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 6998861
PedroG, feedback pls...
0
 
LVL 2

Author Comment

by:PedroG
ID: 6998958
xml is like this

<xmldata>
<filter>data/row[Produto='004']</filter>
<data>
<row>
<Produto>
001
</Produto>
<data>
None
</data>
</row>
</data>
</xmldata>

XSL is something like this
....
<xsl:param filter select="/xmldata/filter">
<xsl:apply-templates select="$filter">

What i want is to use the value of /xmldata/filter to select the Data/row elements

the childs of data/row are dynamic
0
MIM Survival Guide for Service Desk Managers

Major incidents can send mastered service desk processes into disorder. Systems and tools produce the data needed to resolve these incidents, but your challenge is getting that information to the right people fast. Check out the Survival Guide and begin bringing order to chaos.

 
LVL 23

Expert Comment

by:b1xml2
ID: 6999006
>>
the select attribute cannot accept a variable per se but a valid XPath expression.
<<

I have already stated that, what you are trying to do is NOT possible. You will not succeed in a hundred years with the current implementation of the XSLT Engine in every W3C XML Parser.

the select attribute of the xsl:apply-templates MUST accept a valid XPath expression and not any string.

thus, <xsl:apply-templates select="$var" /> will ALWAYS fail.

you will have to use part DOM/part XSLT to achieve this
IF you want to retain your XML Structure
=======================================================
<xmldata>
<filter>//data/row[Produto='004']</filter>
<data>
<row>
<Produto>
001
</Produto>
<data>
None
</data>
</row>
</data>
</xmldata>

First Method
=============
e.g. in client-side, MSXML3
============================
var oXML = new ActiveXObject("Msxml2.DOMDocument");
var oFilter = new ActiveXObject("Msxml2.DOMDocument");
var oXSLT = new ActiveXObject("Msxml2.DOMDocument");
oXML.async = oFilter.async = oXSLT.async = false;
oXML.load("xml/data.xml");
oXSLT.load("xslt/data.xsl");
var oNode = oXML.selectSingleNode("//filter");
if (oNode) oFilter.appendChild(oNode.cloneNode(true));
window.onload = init;
function init() {
 document.all.data = oFilter.transformNode(oXSLT);
}

Notes
=====
1. This is using the DOM to grab nodes.

2. Here, you will have to modify your XSLT.

Second Method
==============
<xmldata>
<filter>
<target name="Produto" value="004" />
</filter>
<data>
<row>
<Produto>
001
</Produto>
<data>
None
</data>
</row>
</data>
</xmldata>

<!--this will use the default settings found in the filter-->
<xsl:call-template name="data" />

<!-- this will change the settings -->
<xsl:call-template name="data">
<xsl:with-param name="value" select="'Check'" />
</xsl:call-template>

<xsl:template name="data">
<xsl:param name="child" select="//filter/target/@name" />
<xsl:param name="value" select="//filter/target/@value" />
<xsl:apply-templates select="//data/row/*[name() = $child and . = $value]" />
</xsl:template>
0
 
LVL 2

Author Comment

by:PedroG
ID: 7001578
it doesn't work. this is my full xml / xsl

<webGrid>
     <config>
          <columns>
               <column Name="Produto" sortable="true" filter="true"/>
               <column Name="Activo" sortable="true" filter="true"/>
               <column Name="Teste" sortable="true" filter="false"/>
          </columns>
          <buttons>
               <button Name="Acrescentar" Action="javascript:AddRow()" ID="Button1"/>
               <button Name="Apagar" Action="javascript:AddRow()" ID="Button2"/>
          </buttons>
          <pages Current="1" Count="20" fetchpageURL="services/GetPage.asp"/>
     </config>
     <data>
          <row>
               <Produto link="admin/teste.asp">Produto 4</Produto>
               <Activo>Sim</Activo>
               <Teste>2002-05-35</Teste>
          </row>
          <row>
               <Produto link="admin/teste.asp">Produto 2</Produto>
               <Activo>Sim</Activo>
               <Teste>2002-04-15</Teste>
          </row>
          <row>
               <Produto link="admin/Teste.asp">Produto 1</Produto>
               <Activo>Sim</Activo>
               <Teste>2002-04-25</Teste>
          </row>
     </data>
     <currentinfo>
          <elementid>ms__id4</elementid>
          <sortkey>activo</sortkey>
          <filter>
               <element>Produto</element>
               <value>Produto 4</value>
          </filter>
     </currentinfo>
</webGrid>


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

     <xsl:template match="/">
          <xsl:apply-templates/>
     </xsl:template>

     <xsl:template match="/webGrid">
          <xsl:param name="sortKey">
               <xsl:value-of select="/webGrid/currentinfo/sortkey"/>
          </xsl:param>          
          <xsl:param name="filterelement" select="/webGrid/currentinfo/filter/element"/>
          <xsl:param name="filtervalue" select="/webGrid/currentinfo/filter/value"/>
          element:<xsl:value-of select="$filterelement"/><br/>
          value:<xsl:value-of select="$filtervalue"/><br/>
          <xsl:apply-templates select="config"/>
          <xsl:apply-templates select="//data/row/*[name(.) = $filterelement and . = $filtervalue]">
               <xsl:sort select="*[name(.)=$sortKey]"/>
          </xsl:apply-templates>
     </xsl:template>
     
     <xsl:template match="config">
          <table>
               <tr>
                    <xsl:apply-templates select="columns/column"/>
               </tr>
          </table>
     </xsl:template>

     <xsl:template match="column">
          <td><xsl:value-of select="@Name"/></td>
     </xsl:template>
     
     <xsl:template match="row">
          <xsl:param name="currentRow" select="(.)"/>
          <BR/>TEMPLATE ROW<BR/>
          <xsl:for-each select="/webGrid/config/columns/column">
               <xsl:variable name="currentCol" select="@Name"/>
               <xsl:value-of select="@Name"/>:<xsl:value-of select="$currentRow/*[name(.)=$currentCol]"/><BR/>
          </xsl:for-each>
     </xsl:template>
     
</xsl:stylesheet>
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 7001618
What exactly do you wish to be achieved with your XSLT? What is it that you want to do ?

The HTML Output is:-
element:Produto<br />
value:Produto 4<br />
<table>
<tr>
<td>Produto</td>
<td>Activo</td>
<td>Teste</td>
</tr>
</table>
Produto 4

and what you are using:
>>
  <xsl:apply-templates select="//data/row/*[name(.) = $filterelement and . = $filtervalue]">
<<
is what I recommended. Pls let me know what HTML output are you expecting  so that I can help you.
0
 
LVL 2

Author Comment

by:PedroG
ID: 7001640
this is a test html
but i was expecting something like

<table>
<tr>
<td>Produto</td>
<td>Activo</td>
<td>Teste</td>
Pruduto 4<br/>sim<br/>2002-05-35
</tr>
</table>
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 7001743
that's not valid HTML.
perhaps, you meant
HTML Output
===========
<table>
<tr>
<td>Produto</td>
<td>Activo</td>
<td>Teste</td>
</tr>
<tr>
<td>Pruduto 4</td>
<td>sim</td>
<td>2002-05-35</td>
</tr>
</table>


XSLT Document
==============
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" encoding="iso-8859-1" />
<xsl:key name="data" match="row/*" use="generate-id(..)" />
<xsl:template match="/">
  <xsl:apply-templates select="webGrid/config" />
</xsl:template>

<xsl:template match="config">
<xsl:variable name="sortKey" select="//currentinfo/sortkey"/>
<xsl:variable name="filterelement" select="//currentinfo/filter/element"/>
<xsl:variable name="filtervalue" select="//currentinfo/filter/value"/>
<table>
<tr>
  <xsl:apply-templates select="columns/column"/>
</tr>
<xsl:apply-templates select="//row[*[name() = $filterelement and . = $filtervalue]]" />
</table>
</xsl:template>

<xsl:template match="column">
<td><xsl:value-of select="@Name"/></td>
</xsl:template>
   
<xsl:template match="row">
<xsl:variable name="id" select="generate-id()" />
<tr>
  <xsl:for-each select="//columns/column/@Name">
  <xsl:apply-templates select="key('data',$id)[name(.) = current()]" />
  </xsl:for-each>
</tr>
</xsl:template>

<xsl:template match="row/*">
<td><xsl:value-of select="." /></td>
</xsl:template>
   
</xsl:stylesheet>
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 7001748
a slight amendment so that the sorting can be achieved.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" encoding="iso-8859-1" />
<xsl:key name="data" match="row/*" use="generate-id(..)" />
<xsl:template match="/">
  <xsl:apply-templates select="webGrid/config" />
</xsl:template>

<xsl:template match="config">
<xsl:variable name="sortKey" select="//currentinfo/sortkey"/>
<xsl:variable name="filterelement" select="//currentinfo/filter/element"/>
<xsl:variable name="filtervalue" select="//currentinfo/filter/value"/>
<table>
<tr>
  <xsl:apply-templates select="columns/column"/>
</tr>
<xsl:apply-templates select="//row[*[name() = $filterelement and . = $filtervalue]]">
<xsl:sort select="*[name() = $sortKey]" />
</xsl:apply-templates>
</table>
</xsl:template>

<xsl:template match="column">
<td><xsl:value-of select="@Name"/></td>
</xsl:template>
   
<xsl:template match="row">
<xsl:variable name="id" select="generate-id()" />
<tr>
  <xsl:for-each select="//columns/column/@Name">
  <xsl:apply-templates select="key('data',$id)[name(.) = current()]" />
  </xsl:for-each>
</tr>
</xsl:template>

<xsl:template match="row/*">
<td><xsl:value-of select="." /></td>
</xsl:template>
   
</xsl:stylesheet>
0
 
LVL 23

Accepted Solution

by:
b1xml2 earned 200 total points
ID: 7067445
<recommendation>
points to b1xml2
</recommendation>
0

Featured Post

The Orion Papers

Are you interested in becoming an AWS Certified Solutions Architect?

Discover a new interactive way of training for the exam.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction In my previous article (http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/SSIS/A_9150-Loading-XML-Using-SSIS.html) I showed you how the XML Source component can be used to load XML files into a SQL Server database, us…
Many times as a report developer I've been asked to display normalized data such as three rows with values Jack, Joe, and Bob as a single comma-separated string such as 'Jack, Joe, Bob', and vice versa.  Here's how to do it. 
Come and listen to Percona CEO Peter Zaitsev discuss what’s new in Percona open source software, including Percona Server for MySQL (https://www.percona.com/software/mysql-database/percona-server) and MongoDB (https://www.percona.com/software/mongo-…
This video Micro Tutorial shows how to password-protect PDF files with free software. Many software products can do this, such as Adobe Acrobat (but not Adobe Reader), Nuance PaperPort, and Nuance Power PDF, but they are not free products. This vide…

729 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question