我想知道是否有任何方法可以创建行为类似于的自定义函数/元素<xsl:for-each/>
我知道有一种方法可以注册 function/element,但是(据我所知)这些都不能更改上下文并递归地执行内部 XSLT 指令。
例如,我想要实现的是:
<myxsl:change-context name='x'>
<xsl:value-of select='name()'/>
</myxsl:change-context>
我想知道是否有任何方法可以创建行为类似于的自定义函数/元素<xsl:for-each/>
我知道有一种方法可以注册 function/element,但是(据我所知)这些都不能更改上下文并递归地执行内部 XSLT 指令。
例如,我想要实现的是:
<myxsl:change-context name='x'>
<xsl:value-of select='name()'/>
</myxsl:change-context>
可以通过插入传递给转换函数的上下文对象来修改 XPath 上下文:
void transformFunction(xsltTransformContextPtr ctxt,
xmlNodePtr node,
xmlNodePtr inst,
xsltElemPreCompPtr comp)
{
xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
/* Save old context */
xmlNodePtr oldNode = ctxt->node;
int oldSize = xpctxt->contextSize;
int oldPos = xpctxt->proximityPosition;
/* Set up your new context... */
ctxt->node = newNode;
xpctxt->contextSize = newSize;
xpctxt->proximityPosition = newPos;
/*
* Do something under new context, probably using
* xsltApplySequenceConstructor...
*/
/* Restore old context */
ctxt->node = oldNode;
xpctxt->contextSize = oldSize;
xpctxt->proximityPosition = oldPos;
}
您可能还必须保存和恢复一些其他上下文变量。看看libxslt如何xsltForEach
在libxslt/transform.c
内部实现。for-each
根据@nwellnholf 的建议,我检查了transform.c,过了一段时间我想出了如何实现它。
xsltApplySequenceConstructor
正如@nwellnholf 所写,核心魔法在里面。为了能够使用它,有必要编辑库并将此函数公开,因为最初此函数仅在 transform.c 中定义。为此,请在 transform.h 中定义它并重新编译 libxslt。
XSLTPUBFUN void xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr list, xsltTemplatePtr templ);
第二步是实现自己的xslt函数,继续自己的指令并将处理返回给xslt。这些步骤通过以下命令完成:
void elemChangeContext(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltElemPreCompPtr /*comp*/)
{
if ( ctxt == NULL || node == NULL || inst == NULL || ctxt->insert == NULL )
return;
xmlNodePtr cur = /* change context to different node */;
xmlNodePtr curInst = inst->children; //sub xslt instruction
xsltApplySequenceConstructor(ctxt,cur, curInst,NULL);
}