Re: [xslt] exsl:tokenize() problem



Le jeudi 10 mars 2005 Ã 17:55 -0500, Daniel Veillard a Ãcrit :
> On Thu, Mar 10, 2005 at 11:26:07PM +0100, Nicolas Mailhot wrote:
> > 1. Am I doing something incredibly stupid ?
> 
>   Maybe maybe not it's hard to tell from just a fragment.

Ok, I'm attaching the whole thing (it's not too big, just ugly since
it's intended as an early proof-of-concept and I never cleaned it up)

> I suggest you run both stylesheets with xsltproc in -v verbose mode
> and compare the output on stderr, then you will see what the
> evaluation of exsl:tokenize() did, and possibly what's actually
> going on.

I think the problem here is the changing of document context (but why is
it affecting keys ? Aren't keys supposed to be more or less stable when
transformation begins ?)

--- without-tokenize.log        2005-03-11 15:30:53.000000000 +0100
+++ with-tokenize.log   2005-03-11 15:31:51.000000000 +0100
@@ -91,10 +91,16 @@
 Evaluating variable expanded
 reusing transformation dict for RVT
 xsltApplyOneTemplate: copy node classpath
+xsltForEach: select exsl-str:tokenize('foo', ':; ')
+Lookup function {http://exslt.org/strings}tokenize
+found function tokenize
+reusing transformation dict for RVT
+xsltForEach: select evaluates to 1 nodes
+xsltForEach: Changing document - context doc index.xml, xpathdoc (null)
 call-template: name findelem
 Handling param pathname
-        select 'foo'
-Building variable pathname select 'foo'
+        select string(.)
+Building variable pathname select string(.)
 Evaluating variable pathname
 Object is a string : foo
 applying template 'findelem'

> > 2. If the answer is yes, what would be the correct way to achieve the
> > same results ?
> > 3. If the answer is no, did I just hit a libxslt bug ? Can it be fixed
> > in the near future or should give up on this transformation ?
> 
>   it could be a bug, but I didn't dot any exslt:tokenize bug report
> recently, so it seems to work as expected.

Well it certainly does not work as expected here;( But since I never
really played with tokenize before, maybe it's my expectations which are
wrong.

Attaching the problem xslt with 4 small xmls to apply on. The command I
use on it is :

xsltproc --xinclude --stringparam path foo pathtest.xsl index.xml

You can compare the behaviour by uncommenting one of the three xslt
blocks around the call to tokenize (the first one calls tokenize on path
which is what I ultimately want to do, the second one uses an hardcoded
path value without tokenize, the third one the same hardcoded value with
tokenize. Right now the hardcoded bit is tokenizing in a single value so
2. and 3. should produce the same results)

I'm pretty ashamed of the state of the stylesheet - I really did not
think I would be showing it up at this stage, but the problem area
should not be too difficult to parse (it's exactly what I posted before)

Regards,

-- 
Nicolas Mailhot
<?xml version="1.0"?>
<pathelem name="bar" version="d.e.f">

  <config file="bar"/>
  <classes file="barA"/>
  <classes file="barBCD"/>

  <implements>
   <pathelem name="barA"/>
   <pathelem name="barB"/>
   <pathelem name="barC"/>
  </implements>

</pathelem>

<?xml version="1.0"?>
<pathelem name="foo" version="a.b.c">

  <config file="foo/fooconf"/>
  <config file="/usr/share/xml/foo/foo" ext="xml"/>
  <config dir="/usr/share/foo-common" version="v.w.x"/>
  <config dir="/usr/share/foo"/>
  <classes file="foo-core"/>
  <classes file="foo-lib"/>
  <classes file="foo-contrib" ext="zip" version="d.e.f"/>
  <classes libdir="/usr/share/foo/lib" version=""/>

  <depends>
    <pathelem name="barA"/>
    <pathelem name="barB" version="d.e.f"/>
    <pathelem name="barC" minver="d.e.f" maxver="x.y.z"/>
  </depends>

  <conflicts>
   <java minver="1.5.0"/>
   <jvm name="java-ibm" maxver="1.3.1"/>
   <pathelem name="toto" version="x.y.y"/>
  </conflicts>

  <implements>
   <pathelem name="bob"/>
   <pathelem name="bill" minver="e.r.t"/>
  </implements>

  <native>
   <dir name="/usr/lib/java"/>
   <dir name="/opt/oracle/oracle-x-y-z/lib"/>
  </native>

</pathelem>

<?xml version="1.0"?>
<java xmlns:xi="http://www.w3.org/2003/XInclude";>

 <xi:include href="policy.xml"/>

 <pathelems>
  <xi:include href="foo-a.b.c.xml"/>
  <xi:include href="bar-d.e.f.xml"/>
 </pathelems>

</java>
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                xmlns:exsl="http://exslt.org/common"; 
                xmlns:exsl-str="http://exslt.org/strings";
                extension-element-prefixes="exsl exsl-str"
                version="1.0">
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
  <xsl:key name="pathelems" match="/java/pathelems/pathelem" use="@name"/>
  <xsl:key name="virtuals" match="/java/pathelems/pathelem/implements/pathelem" use="@name"/>
  <xsl:param name="path" required="yes"/>

  <xsl:template match="/">
    <xsl:variable name="expanded">
      <classpath name="expanded">
        <!-- <xsl:apply-templates select="exsl-str:tokenize($path, ':; ')" mode="findelem"/> -->
    
    <!--<xsl:call-template name="findelem">
      <xsl:with-param name="pathname" select="'foo'"/>
    </xsl:call-template>-->

      <xsl:for-each select="exsl-str:tokenize('foo', ':; ')">
        <xsl:call-template name="findelem">
          <xsl:with-param name="pathname" select="string(.)"/>
        </xsl:call-template>
      </xsl:for-each>

      </classpath>
    </xsl:variable>
    <!-- Remove duplicate pathelems -->
    <xsl:variable name="trimmed">
      <classpath name="trimmed">
        <xsl:for-each select="exsl:node-set($expanded)/classpath/pathelem">
          <xsl:variable name="name" select="@name"/>
          <xsl:variable name="version" select="@version"/>
          <xsl:if test="not(preceding-sibling::pathelem[ name = $name and @version = $version])">
            <xsl:copy-of select="."/>
          </xsl:if>
        </xsl:for-each>
      </classpath>
    </xsl:variable>
    <!-- Add roots specified by policy -->
    <xsl:variable name="classpath">
      <classpath name="classpath">
        <xsl:for-each select="exsl:node-set($trimmed)/classpath/pathelem">
          <pathelem>
            <xsl:for-each select="@*">
              <xsl:copy-of select="."/>
            </xsl:for-each>
            <xsl:for-each select="config|classes">
              <pathbit>
                <xsl:copy-of select="prefix|postfix|extension|version"/>
                <xsl:choose>
                  <xsl:when test="prefix[starts-with(.,'/')]">
                    <root>/</root>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:copy-of select="root"/>
                  </xsl:otherwise>
                </xsl:choose>
              </pathbit>
            </xsl:for-each>
          </pathelem>
        </xsl:for-each>
      </classpath>
    </xsl:variable>
    <xsl:copy-of select="$classpath"/>
  </xsl:template>

  <!-- Recurse on dependencies -->
  <xsl:template match="depends/pathelem" priority="1">
    <xsl:call-template name="findelem">
      <xsl:with-param name="pathname" select="@name"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="pathelem" priority="0">
    <pathelem>
      <xsl:for-each select="@*">
        <xsl:copy-of select="."/>
      </xsl:for-each>
      <xsl:apply-templates select="config" mode="full"/>
      <xsl:apply-templates select="classes" mode="full"/>
    </pathelem>
    <xsl:apply-templates select="depends/pathelem"/>
  </xsl:template>

  <xsl:template match="token[contains(.,'-')]" mode="findelem" priority="1">
    <xsl:message>Calling findelem on element <xsl:value-of select="substring-before(string(.),'-')"/> with version <xsl:value-of select="substring-after(string(.),'-')"/></xsl:message>
    <xsl:call-template name="findelem">
      <xsl:with-param name="pathname" select="substring-before(string(.),'-')"/>
      <xsl:with-param name="version"  select="substring-after(string(.),'-')"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="token" mode="findelem" priority="0">
     <xsl:message>Calling findelem on element <xsl:value-of select="."/> with no version</xsl:message>
    <xsl:call-template name="findelem">
      <xsl:with-param name="pathname" select="."/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="findelem">
    <xsl:param name="pathname" required="yes"/>
    <xsl:param name="version" required="no"/>
    <xsl:message>Executing findelem on <xsl:value-of select="$pathname"/> with version <xsl:value-of select="$version"/>
                 Number of matching pathelems : <xsl:value-of select="count(key('pathelems',$pathname))"/>
    </xsl:message>
    <xsl:choose>
      <xsl:when test="count(key('pathelems',$pathname))>0">
        <xsl:apply-templates select="key('pathelems',$pathname)[1]"/>
      </xsl:when>
      <xsl:when test="count(key('virtuals',$pathname))>0">
        <xsl:apply-templates select="key('virtuals',$pathname)[1]/../.."/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message>Could not find matching classpath element for <xsl:value-of select="$pathname"/></xsl:message>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="config|classes" mode="full">
    <xsl:variable name="name" select="name()"/>
    <xsl:element name="{$name}">
      <xsl:apply-templates select="." mode="prefix"/>
      <xsl:apply-templates select="." mode="version"/>
      <xsl:for-each select="/java/policy/*[name()=$name]">
        <root>
          <xsl:value-of select="@path"/>
        </root>
      </xsl:for-each>
    </xsl:element>
  </xsl:template>

  <!-- Simplify user-provided pathelem descriptors
       - add default values
       - use simpler less compact naming -->

  <xsl:template match="*[ dir and (self::config or self::classes)]" mode="prefix">
    <prefix>
      <xsl:value-of select="@dir"/>
    </prefix>
    <postfix>/</postfix>
  </xsl:template>

  <xsl:template match="classes[ libdir]" mode="prefix">
    <prefix>
      <xsl:value-of select="@libdir"/>
    </prefix>
    <postfix>/*</postfix>
  </xsl:template>

  <xsl:template match="*[ file and (self::config or self::classes)]" mode="prefix">
    <prefix>
      <xsl:value-of select="@file"/>
    </prefix>
    <xsl:apply-templates select="." mode="postfix"/>
  </xsl:template>

  <xsl:template match="*[ file and @ext and (self::config or self::classes)]" mode="postfix" priority="1">
    <postfix>
      <xsl:value-of select="concat('.',@ext)"/>
    </postfix>
  </xsl:template>

  <xsl:template match="config[ file]" mode="postfix" priority="0">
    <postfix>.properties</postfix>
  </xsl:template>

  <xsl:template match="classes[ file]" mode="postfix" priority="0">
    <postfix>.jar</postfix>
  </xsl:template>

  <xsl:template match="*[ version and (self::config or self::classes)]" mode="version" priority="1">
    <version>
      <xsl:value-of select="@version"/>
    </version>
  </xsl:template>

  <xsl:template match="config|classes" mode="version" priority="0">
    <version>
      <xsl:value-of select="../@version"/>
    </version>
  </xsl:template>

</xsl:stylesheet>
<?xml version="1.0"?>
<!-- Java policy setup:
     - paths to use in priority order
     - virtual weights ?
     -->
<policy>

 <config path="~/.system/etc/java"/>
 <config path="~/.java/etc"/>
 <config path="/etc/java"/>
 
 <classes path="~/.system/share/java"/>
 <classes path="~/.java/lib"/>
 <classes path="/usr/share/java"/>

</policy>

Attachment: signature.asc
Description: This is a digitally signed message part



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]