dyn:evaluate()没有正确评估?

时间:2015-03-08 04:47:02

标签: php xslt xpath exslt

由于某种原因,我的XPath查询在通过dyn:evaluate()在XSLT中执行时不起作用。我正在使用PHP并hasEXSLTSupport()评估为true

这是我的原始XML文档:

<getListValues>
    <node>
        <Assignee>Assignee Value</Assignee>
        <Summary>Summary Value</Summary>
        <Incident_Number>Incident_Number Value</Incident_Number>
    </node>
</getListValues>

我正在使用此XPath语句:

//node[Assignee!=""]/*[name()="Summary" or name()="Incident_Number" or  name()="Assignee"]

在我的XSLT中,我正在使用此部分来检查它是否有效:

<xsl:variable name="elementValue" select="dyn:evaluate($query)" />
<xsl:value-of select="$elementValue" />

$query评估带有XPath表达式的字符串(我知道,因为我也检查了xsl:value-of)。

我没有收到任何错误。实际上,执行<xsl:value-of select="boolean($elementValue)" />评估为false!这意味着它没有得到任何回报。

我的样式表标题是:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dyn="http://exslt.org/dynamic" xmlns:php="http://php.net/xsl" extension-element-prefixes="dyn">

似乎XPath只是没有得到评估,即使它完全有效(我查看了PHP和Notepad ++的XPatherizerNPP扩展)。我错过了什么?

修改

我的实际脚本在几个类和文件夹中,所以我发布了一个更简单的版本,我正在运行。它在dyn中是等价的:即使Notepad ++告诉我应该这样做,evaluate()仍然不起作用,并且我只是将其他类中的复制粘贴函数合并为一个以便于参考。

我的 mock.xml 是我要解析的脚本

<getListValues>
<node>
    <Assignee>Assginee Value</Assignee>
    <Summary>Summary Value</Summary>
    <Incident_Number>Incident_Number Value</Incident_Number>
</node>

我的countFieldValues.xml样式表调用PHP在readSubtree php函数调用中一次解析单个子树。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dyn="http://exslt.org/dynamic" xmlns:php="http://php.net/xsl" extension-element-prefixes="dyn">

    <xsl:output method="html" omit-xml-declaration="yes" />

    <xsl:template match="/">
        <xsl:call-template name="nodeIterate" />
    </xsl:template>

    <xsl:template name="nodeIterate">
        <xsl:variable name="subtree" select="php:functionString('xsltMaster::readSubtree', $dataset)" />
        <xsl:if test="boolean($subtree)">
            <xsl:apply-templates select="$subtree"/>
            <xsl:call-template name="nodeIterate" />
        </xsl:if>
    </xsl:template>

    <xsl:template match="node">
        <br/>The current node: <xsl:value-of select="." /><br/>
        <br/>The query: <xsl:value-of select="$query" /><br/>
        <xsl:variable name="elementValue" select="dyn:evaluate($query)" />
        <br/>What dyn:evaluate() evaluates to: <xsl:value-of select="boolean($elementValue)" /><br/>
        <xsl:if test="boolean($elementValue)">
            <xsl:for-each select="$elementValue">
                <br/>What dyn:evaluate() evaluates to specifically: <xsl:value-of select="$elementValue" /><br/><br/>
            </xsl:for-each>
            <!--<xsl:variable name="archivist" select="php:functionString('xsltMaster::storeCount', $element, $elementValue)" />-->
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

我的testscript.php调用该类并执行所有操作

<?php

require_once "class.php";
$source = "countFieldValues.xml";

$query = '//node[Assignee!=""]/*[name()="Summary" or name()="Incident_Number" or  name()="Assignee"]';
$test4 = new xsltMaster;
$test4->createXSLT($source);

$test4->processDataSet($query, "mock.xml", "processedMock.json");

我的 class.php 是处理器。它使用PHP中的XMLReader和XSLTProcessor类。

<?php
class xsltMaster{

    protected static $_read;
    private $_xslt;
    protected $_dom;

    public function __construct(){
        // load DOM XML
        $this->_dom = new DOMDocument();
        $this->_dom->loadXML('<root />');
    }

    /*
        Creates the XSLT object on the currently loaded DOM document
        If the XSLT is already loaded, it will delete it
        It will then load the stylesheet
    */
    public function createXSLT($xsl){
        if(!empty($this->getXSLT())){
            $this->deleteXSLT();
        }
        $xsldoc = new DOMDocument();
        if(!$xsldoc->load($xsl)){
            throw new PDOException('Failed to open XML stylesheet!');
        }
        $this->getXSLT(new XSLTProcessor())->importStyleSheet($xsldoc);
        unset($xsldoc);

        return true;
    }

    /*
        Getters/setters for the XSLT processor
    */
    protected function getXSLT($xslt=false){
        if(!empty($xslt)){
            $this->_xslt = $xslt;
        }
        return $this->_xslt;
    }


    // this will register PHP functions and run PHP XMLReader inside XSLT
    public function processDataSet($query, $source, $destination){
        // set-up
        $this->getXSLT()->registerPHPFunctions();
        $this->getXSLT()->setParameter('', 'query', $query);
        $this->getXSLT()->setParameter('', 'dataset', $source);
        $this->getXSLT()->setProfiling('profile9.txt');
        echo "has EXSLT support? ", var_dump($this->getXSLT()->hasEXSLTSupport()), "<br/>";

        // execute
        print $this->getXSLT()->transformToXML($this->_dom);
        #file_put_contents($destination, json_encode(self::$_countList));

        // clean up
        $this->getXSLT()->removeParameter('', 'dataset');
        $this->getXSLT()->removeParameter('', 'query');
    }

    public static function readSubtree($url=false){
        // check if reader has already been initialized
        if(empty(self::$_read)){
            // if reader has not been initialized, check if a url is supplied
            if(empty($url)) throw new PDOException("There is no file defined for transformation!");
            // create the reader
            self::$_read = new XMLReader;
            self::$_read->open($url);
            // loop until you reach the first node
            while (self::$_read->name !== 'node'){
                self::$_read->read();
            }
        } else {
            // if the logic gets here, the reader has already initialized
            // just move to the next node
            self::$_read->next();
        }
        // once you find the first subtree, return it
        // as long as we're still landing on a node element, return that expanded subtree
        if(self::$_read->name === 'node'){
            #echo "<pre>",var_dump(self::$_read->getReader()->expand()),"</pre>";
            return self::$_read->expand();
        }
        // if it gets here, then we're at the bottom of the file
        return null;
    }

}

更新

我找到了dyn:evaluate()确实返回节点集的一些表达式。 但他们有点奇怪。

这是他们评价为真的时候:

Assignee
Summary
Incident Number
*[name()="Assignee"]
*[name()="Assignee" and text()="Assignee Value"]

但这些评价为假:

*[Assignee="Assignee Value"]
//Assignee

这是什么交易......?

更新

根据迈克尔的建议,我运行了他的测试并得到了这个结果:

<?xml version="1.0" encoding="UTF-8"?>
<results>
  <processor>libxslt</processor>
  <support>true</processor>
  <path>/root/bravo</path>
  <target/>
</results>

失败部分是目标是一个空元素。

1 个答案:

答案 0 :(得分:1)

我建议您尝试更简单的测试并报告结果:

<强> XML

<root>
    <alpha/>
    <bravo/>
    <charlie/>
</root>

<强> XSLT

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

<xsl:param name="path" select="'/root/charlie'"/>

<xsl:template match="/">
    <results>
        <processor>
            <xsl:value-of select="system-property('xsl:vendor')"/> 
        </processor>
        <support>
            <xsl:value-of select="function-available('dyn:evaluate')"/>
        </support>
        <path>
            <xsl:value-of select="$path"/>
        </path> 
        <target>
            <xsl:copy-of select="dyn:evaluate($path)"/>
        </target>   
    </results>
</xsl:template>

</xsl:stylesheet>

<强>参数

path = "/root/bravo"

预期结果

<?xml version="1.0" encoding="UTF-8"?>
<results>
  <processor>libxslt</processor>
  <support>true</support>
  <path>/root/bravo</path>
  <target>
    <bravo/>
  </target>
</results>

2

回应您的结果:

dyn:evaluate()不起作用,尽管有指示,或者你传递参数的方式有问题。这可以通过在测试中再添加一个元素来确定:

<verify>
    <xsl:copy-of select="dyn:evaluate('/')"/>
</verify>

3

请再试一次:

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

<xsl:param name="path" select="'/root/charlie'"/>

<xsl:template match="/">
    <results>
        <processor>
            <xsl:value-of select="system-property('xsl:vendor')"/> 
        </processor>
        <support>
            <xsl:value-of select="function-available('dyn:evaluate')"/>
        </support>
        <path>
            <xsl:value-of select="$path"/>
        </path> 
        <eval-param>
            <xsl:copy-of select="dyn:evaluate($path)"/>
        </eval-param>   
        <eval-string>
            <xsl:copy-of select="dyn:evaluate('/root/charlie')"/>
        </eval-string>  
        <copy>
            <xsl:copy-of select="/root/charlie"/>
        </copy> 
    </results>
</xsl:template>

</xsl:stylesheet>