tags:

views:

537

answers:

3

Hi I have a following xslt code :

<xsl:template match="table_terms_and_abbr">
    <informaltable frame='none' colsep='none' rowsep='none'>
        <tgroup cols='2' align='left'>
            <colspec colnum="1" colwidth='1*'/>
            <colspec colnum="2" colwidth='1*'/>
            <xsl:apply-templates/>
        </tgroup>     
    </informaltable>
</xsl:template>

and the following xml that it's processing :

<table_terms_and_abbr>
        <tblrow_hdr>Name ,, Description</tblrow_hdr>
        <tbody>
            <tblrow_bold_first> BOT ,, &j_bot;</tblrow_bold_first>
            ...
        </tbody>    
</table_terms_and_abbr>

Now i want to improve the xslt by moving following lines inside the table_terms_and_abbr:

<tblrow_hdr>Name ,, Description</tblrow_hdr>
<tbody>

</tbody>

So i will have something like :

<xsl:template match="table_terms_and_abbr">
    <informaltable frame='none' colsep='none' rowsep='none'>
        <tgroup cols='2' align='left'>
            <colspec colnum="1" colwidth='1*'/>
            <colspec colnum="2" colwidth='1*'/>
             <xsl:call-template name="tblrow_hdr">
                  BOT ,, &j_bot;                      * ???? *
             </xsl:call-template>
            <tbody>
            <xsl:apply-templates/>
            </tbody>
        </tgroup>     
    </informaltable>
</xsl:template>

The line marked with * ???? * does not work. I using saxon9 (xslt 2.0 stylesheet) on linux platform and got this error:

XTSE0010: No character data is allowed within xsl:call-template

I know how to pass the attributes to the template i.e:

<xsl:with-param name="is_make_first_bold" select = "1" as="xs:integer"/>

but how to pass free text ?

The idea is move to the template all static data and in xml only use variable data i.e

<table_terms_and_abbr>
    <tblrow_bold_first> BOT ,, &j_bot;</tblrow_bold_first>
    ...
</table_terms_and_abbr>

More Info
My requirement was to create a simplified syntax for defining repeatable tables for our DocBook documentation. For that i created a general named template tblrow that will split the line delimited by ",," to separate entities and will create a list of entries in the table row.
Each entry can be a simple string, an ENTITY or another template. Since the parameter numbers are undefined (the tables can have different number of cells) i can't use a standard parameters for the templates and used delimited string. If i want to have one of the table entries to contain a link to some place in the document i can't use the parameters again since i can't pass xref template as a parameter.
The main reason not to change the tblrow template is that it's working :) and it's kind of complex. It's took me ages to achieve this and I'm not completely understand how it's working :).

Now on top of this i have a few variables that can control the displayed output like tblrow_hdr that will underline and bold the text in each entry. Since tblrow_hdr is common for all table_terms_and_abbr tables it just sounds logical to me not having this in xml rather put the call to the tblrow_hdr inside the table_terms_and_abbr template and here i stuck.

+2  A: 

I know how to pass the attributes to the template i.e:

<xsl:with-param name="is_make_first_bold" select = "1" as="xs:integer"/>

but how to pass free text ?

Pass the text as the content of an xsl:with-param element.

XSL Transformations 11.6 Passing Parameters to Templates

<xsl:with-param
  name = qname
  select = expression>
  <!-- Content: template -->
</xsl:with-param>

Parameters are passed to templates using the xsl:with-param element. The required name attribute specifies the name of the parameter (the variable the value of whose binding is to be replaced). The value of the name attribute is a QName, which is expanded as described in [2.4 Qualified Names]. 'xsl:with-param' is allowed within both xsl:call-template and xsl:apply-templates. The value of the parameter is specified in the same way as for xsl:variable and xsl:param. The current node and current node list used for computing the value specified by xsl:with-param element is the same as that used for the xsl:apply-templates or xsl:call-template element within which it occurs. It is not an error to pass a parameter x to a template that does not have an xsl:param element for x; the parameter is simply ignored.

This example defines a named template for a numbered-block with an argument to control the format of the number.

<xsl:template name="numbered-block">
  <xsl:param name="format">1. </xsl:param>
  <fo:block>
    <xsl:number format="{$format}"/>
    <xsl:apply-templates/>
  </fo:block>

<xsl:template match="ol//ol/li">
  <xsl:call-template name="numbered-block">
    <xsl:with-param name="format">a. </xsl:with-param>
  </xsl:call-template>
</xsl:template>
ddaa
so i will need to change the tblrow_bold_first template to receive parameter? I would like to avoid this. In the worst case i will not optimize and will repeat the lines in xml.
Ilya
Either you include the text in the template, or you pass it in the template as a parameter, or you format it from the source document. I do not know what you want to do, just answering the specific technical questions.
ddaa
i will try to add more info in the question.
Ilya
+1  A: 

You can pass the additional string data as a parameter:

     <xsl:with-param name="pNeededText" select="'--123Abc'"/>

and in the called template define this parameter:

     <xsl:param name="pNeededText" as="xs:string">

Or, you could define a global <xsl:variable/> or <xsl:param/> and reference it directly in the called template.

Dimitre Novatchev
+1  A: 
> Since the parameter numbers are
> undefined (the tables can have
> different number of cells) i can't use
> a standard parameters for the
> templates and used delimited string.
Actually, this is not so. Here is an example of an
<xsl:with-param/>
, the body of which is a node-set that may consist of different number of elements on different calls:
    <xsl:template match="/">
      <xsl:variable name="vrtfTParams">
        <p>xxx</p>
        <p>yyy</p>
        <p>zzz</p>
      </xsl:variable>

      <xsl:call-template name="makeTable">
        <xsl:with-param name="pTParams"
         select="msxsl:node-set($vrtfTParams)/*"/>
      </xsl:call-template>
    </xsl:template>

The "makeTable" template can be as simple as this:

    <xsl:template name="makeTable">
      <xsl:param name="pTParams"/>

      <table>
        <tr>
          <xsl:for-each select="$pTParams">
            <td>
              <xsl:value-of select="."/>
            </td>
          </xsl:for-each>
        </tr>
      </table>
    </xsl:template>

The msxsl:node-set() extension function can be used with a Microsoft XSLT processor. Most other processors support the exslt:node-set() extension function (Microsoft's .Net XSLT processor XslCompiledTransform also supports it).

In case the contents of $vrtfTParams is not dynamically generated (as is the case in this example), no xxx:node-set() function is necessary, because the contents of the <xsl:variable> can be passed like this:

 <xsl:with-param name="pTParams"
   select="document('')/*/xsl:variable[name()=vrtfTParams)/*"/>

Here $vrtfTParams must be globally defined (a child of <xsl:template/>).

In XSLT 2.0 (and XPath 2.0) there is no RTF type and no xxx:node-set() extension function is needed at all.

Hope this helped.

Cheers,

Dimitre Novatchev

Dimitre Novatchev
Ilya
Ask another question about this. There is a standard XPath 2.0 tokenize() function. In XSLT 1.0 one can write a recursive template or use FXSL's str-split-to-words template. As I said, this is a totally different question and probably this was your main question in the first place.
Dimitre Novatchev