Search code examples
xsltdocbook

Using processing instructions to set a variable in XSLT


I'm using asciidoc with the docbook backend, and I'm trying to pass a URL as a variable from asciidoc through to docbook, where the variable can have different values throughout the document. For instance, I want my users to be able to do something like:

# url="http://foo/

== some text

Some para....

# url="http://bar/

== some text

Some para....

My idea was to use pass through blocks to add processing instructions which could be picked up in docbook, eg:

pass::[<?my_url http://foo ?>]
== some title

some para...

What I can't figure out how to do is to write the XSLT which expresses the following: "find the previous processing-instruction called my_url and use its contents to set the value of a variable"

Following the guidance given in http://www.sagehill.net/docbookxsl/ProcessingInstructions.html I tried using a dbhtml PI, eg:

<?dbhtml my_url="http://foo.com" ?>

and in my XSL:

  <xsl:template match="ulink[@role='edit_me']">
    <xsl:variable name="my_url">  
      <xsl:call-template name="dbhtml-attribute">  
        <xsl:with-param name="pis"  
             select="ancestor-or-self::entry/processing-instruction('dbhtml')"/>  
        <xsl:with-param name="attribute" select="'my_url'"/>  
      </xsl:call-template>
    </xsl:variable>

    GOT: <xsl:value-of select="$my_url" />
  </xsl:template>

But I'm completely unable to retrieve the value I'm after. Help gratefully appreciated.

Added example XML

For instance, take this example XML document:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">

<book lang="en">
<bookinfo>
    <title>Title one</title>
</bookinfo>

<?my_url http://foo.com ?>

<preface>
    <title><ulink role="edit_me" url="test.asciidoc">Edit me</ulink></title>
</preface>

<?my_url http://bar.com ?>

<chapter id="_title_two">
    <title>Title two<ulink role="edit_me" url="test.asciidoc">Edit me</ulink></title>
    <simpara>Some text</simpara>
</chapter>

<chapter id="_title_three">
    <title>Title three<ulink role="edit_me" url="test.asciidoc">Edit me</ulink></title>
    <simpara>More text</simpara>
</chapter>

</book>

I want to render each of the edit_me links using the URL specified in the preceding my_url processing instruction. So the first link will use foo.com, while the next two will use bar.com.


Solution

  • You are using:

    select="ancestor-or-self::entry/processing-instruction('dbhtml')"
    

    but there is no entry in your example, and all the processing instructions are children of the root book element.

    It sounds like you really want to grab the value of the closest preceding processing instruction. For example, applying:

    <xsl:template match="ulink[@role='edit_me']">
        <xsl:copy>
        <xsl:attribute name="url">
            <xsl:value-of select="preceding::processing-instruction('my_url')[1]"/>
        </xsl:attribute>
        </xsl:copy>
    </xsl:template> 
    

    (along with the identity transform template and a template to suppress processing-instructions) would result in:

    <?xml version="1.0" encoding="utf-8"?>
    <book lang="en">
       <bookinfo>
          <title>Title one</title>
       </bookinfo>
       <preface>
          <title>
             <ulink url="http://foo.com "/>
          </title>
       </preface>
       <chapter id="_title_two">
          <title>Title two<ulink url="http://bar.com "/>
          </title>
          <simpara>Some text</simpara>
       </chapter>
       <chapter id="_title_three">
          <title>Title three<ulink url="http://bar.com "/>
          </title>
          <simpara>More text</simpara>
       </chapter>
    </book>