Intent

Some features need configuration files that may vary just a little for different situations. This pattern has beed designed to avoid redundancy (by rewriting almost same files) and complexity (by using XSLT) while resolving these different situations.

A XSLT implementation is provided.

Motivation

There are a lot of situations where configuration files only differ a little. To resolve this situation, we may write specific XSLT (or java, ...) code.

To avoid this complexity that decreases maintenance and usability, we may create a filter (like the Role-filter cocoon transformer) in XSLT, that will selects (delete or keeps) elements according the rule provided (and not only the user's role).

For example, if you have the following fragment that describes a form, you may have create and update modes in the same file :

Usage

It may be used when you have files that differ only a little. Two elements, in http://bluexml.org/filter/1.0 namespace, are available :

<?xml version="1.0"?>

<root xmlns:filter="">
    <A>
        <filter:keep-current-element when="onlya"/>
    </A>
    <B>
        <filter:keep-current-element when="nota"/>
    </B>
</root>

It is useful when working with static files. If you dynamically generate your files, generate directly the file you need, I think you will avoid problems.

From a performance point of view, there is no impact because you will use it with configuration files that are usually well cached by the system.

Structure/Architecture

http://www.bluexml.org/static/images/filtering-dp.gif

Component

If you take the above example :

Implementation

This is a very simple implementation that compares condition parameter with @when

<!--|
    | CVS $Id: filter.xsl,v 1.4 2005/08/03 13:41:37 cvsjck Exp $
    |
    | This stylesheet filters elements and deletes or keeps them according they
    | verify the condition or not.
    |
    | @author jck@bluexml.com
    | @copyright 2004-2005 BlueXML SARL. All rights reserved.
    |-->

<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:filter="http://bluexml.org/filter/1.0">
    
<!--|
    | Condition
    | Usually user's role, view, ... To be satisfied, the condition parameter
    | must contain (include) the string in @when attribute
    | For example :
    | * condition = role-dataadmin, when = dataadmin => verified
    | * condition = user-anonymous, when = dataadmin => not verified
    |-->
<xsl:param name="condition">sysadmin-create</xsl:param>
<xsl:param name="log">nodebug</xsl:param>

<!--|
    | For each element, we 'reserve' the element and attribute creation
    | We first check each available rule and apply it
    | Finally we eventually copy the others attributes
    | which is not correct.
    |
    | @param @when the condition to verify
    | @returns the node if the condition is verified, nothing otherwise
    |
    | @TODO : the conditions admin-create and create are realized the same way.
    | It may be considered like a bug :-)
    |-->
<xsl:template match="*[filter:delete-current-node]">
    <xsl:variable name="results">
        <xsl:for-each select="filter:delete-current-node">
            <xsl:if test="'debug' = $log">
                When = <xsl:value-of select="@when"/>
            </xsl:if>
            <xsl:if test="contains($condition, @when)">1</xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <xsl:if test="'debug' = $log">
        Results = <xsl:value-of select="$results"/>
        Condition = <xsl:value-of select="$condition"/>
        Result = <xsl:value-of select="contains($condition, @when)"/>
    </xsl:if>
    <xsl:if test="not(contains($results, '1'))">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

<xsl:template match="*[filter:keep-current-node]">
    <xsl:variable name="results">
        <xsl:for-each select="filter:keep-current-node">
            <xsl:if test="'debug' = $log">
                When = <xsl:value-of select="@when"/>
            </xsl:if>
            <xsl:if test="contains($condition, @when)">1</xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <xsl:if test="'debug' = $log">
        Results = <xsl:value-of select="$results"/>
        Condition = <xsl:value-of select="$condition"/>
        Result = <xsl:value-of select="contains($condition, @when)"/>
    </xsl:if>
    <xsl:if test="contains($results, '1')">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()" />
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

More information

This web page is available in html format on http://www.bluexml.org. You may have help on cocoon or bluexml mailing lists.

JCKermagoret

DesignPattern/Filtering (last edited 2009-09-20 23:40:22 by localhost)