1

出于某种原因,当通过 dyn:evaluate() 在 XSLT 中执行时,我的 XPath 查询不起作用。我正在使用 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" />

Where$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 扩展)。我错过了什么?

编辑

我的实际脚本在几个类和文件夹中,所以我发布了我正在运行的更简单的版本。即使 Notepad++ 告诉我应该这样做,它的 dyn: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>

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

4

1 回答 1

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>
于 2015-03-08T05:56:28.393 回答