由于某种原因,我的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>
失败部分是目标是一个空元素。
答案 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>
回应您的结果:
dyn:evaluate()不起作用,尽管有指示,或者你传递参数的方式有问题。这可以通过在测试中再添加一个元素来确定:
<verify>
<xsl:copy-of select="dyn:evaluate('/')"/>
</verify>
请再试一次:
<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>