xsltProcessor setParameter : send an undefined num

2019-02-26 03:57发布

问题:

I have an XSL file.

I have a PHP file with a XSLTProcessor named $bob.

I want to send to my xsl transformation some parameters.

So, I write this in my PHP file; for example :

$bob->setParameter('', 'message', 'hi');

In my XSL file, to get the parameter, I write this for example :

<xsl:param name="message" />

And if i want to display this param in my XSL, I do this :

<xsl:value-of select="$message" />

Here comes the problem.

I have to send to my XSL an undefined number of parameters, and I don't know how to do it. I tried several solutions but they were not relevant. I want to send for example 3 messages to my XSL, and I want my XSL to use them to produce a code like this :

<messages>
    <message>Hi</message>
    <message>it's bob</message>
    <message>How are you ?</message>
</messages>

Do you have a solution for me ? It will be very nice. Sorry if my english has mistakes. Thanks you and have a good day.

As asked, here is what I have and what I want to have :

(the following is separated)

Here is a simplified version of my original XML, named posts.xml :

<posts>
    <post id="post1" >
        <titre>Hey</titre>
        <motscles>
            <motcle>Batman</motcle>
            <motcle>Cats</motcle>
        </motscles>
    </posts>
</posts>

Here is the XML i want to have in final :

<posts>
    <post id="post1" >
        <titre>Hey</titre>
        <motscles>
            <motcle>Batman</motcle>
            <motcle>Cats</motcle>
        </motscles>
    </posts>
    <post id="post2" >
        <titre>Toto</titre>
        <motscles>
            <motcle>Superman</motcle>
            <motcle>Dogs</motcle>
            <motcle>Cake</motcle>
        </motscles>
    </posts>
</posts>

I obtained the information of the post (titre, motscles) by an HTML form. So my php file get the information, and send it to my XSL file :

// initialize xml and xsl
$xml = new DOMDocument();
$xml->load('posts.xml');
$xsl = new DOMDocument();
$xsl->load('addpost.xsl');

// Initialize the XSLTProcessor
$addPost  = new XSLTProcessor();
$addPost->importStylesheet($xsl);

// Define parameters
$addPost->setParameter('', 'titre', $_POST['titre']);

// Get the modified xml
$xml = $addPost->transformToDoc($xml);

// Save the modified xml
$xml->save('posts.xml');

Here is a simplified version of my XSL :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output 
        method="xml"
        indent="yes" 
        encoding="UTF-8"
        />

    <xsl:param name="titre" />
    <xsl:param name="motscles" />

    <xsl:template match="posts" >
        <xsl:copy>

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

            <xsl:call-template name="post" />
        </xsl:copy>
    </xsl:template>

    <!-- Template de post -->
    <xsl:template name="post" >
        <post id="{$id}" >
            <titre><xsl:value-of select="$titre" /></titre>
            <motscles>
            </motscles>
        </post>
    </xsl:template>

    <!-- Copier les nodes et attributs récursivement -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
   </xsl:template>  

</xsl:stylesheet>

回答1:

Well decide on a separator character for your messages (i.e. a character that is ensured not to occur in a message), then pass in a string with the messages separated by that character e.g. if you choose | you pass in $bob->setParameter('', 'message', "Hi|It's Bob|How are you?");, then in your XSLT code to be used with libxslt use e.g.

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0"
  xmlns:str="http://exslt.org/strings"  
  exclude-result-prefixes="str">

<xsl:param name="message"/>

<xsl:variable name="msgs-rtf">
  <messages>
    <xsl:for-each select="str:tokenize($message, '|')">
       <message>
         <xsl:value-of select="."/>
       </message>
    </xsl:for-each>
  </messages>
</xsl:variable>

<xsl:template match="/">
  <xsl:copy-of select="$msgs-rtf"/>
</xsl:template>

</xsl:stylesheet>

As far as I know that extension function str:tokenize is supported in libxslt which PHP 5 uses for XSLT so you should be able to use it. Or you need to write a template that does the tokenization in XSLT itself



回答2:

I would just have one parameter, that is an XML document. I would create this XML document before I invoke the transformation.

This has some definit benefits compared to sending a single, pipe-delimited string:

  1. Every parameter is in its own element and this can be matched by a separate template in XSLT.

  2. No recursive processing of a pipe-delimited string and no extension functions are needed.

  3. More extensible and scalable.



回答3:

How about concatenation in PHP?

$bob->setParameter("", "message", "Hi:it's bob:How are you ?");

and tokenization in XSLT code:

<messages>
<xsl:for-each select="tokenize($message,':')">
<message>
<xsl:value-of select="." />
</message>
</xsl:for-each>
</messages>