2014-10-02 76 views
0

我不知道是否有什么办法如何创建自定义函数/元素,将行为类似于<xsl:for-each/>可以为LibXML/LibXSLT创建自定义函数来更改上下文吗?

我知道有一种方法没有这怎么register function/element,但能(据我所知)更改上下文并递归执行内部XSLT指令。

比如我想实现的是这样的:

<myxsl:change-context name='x'> 
    <xsl:value-of select='name()'/> 
</myxsl:change-context> 
+1

为什么你需要一个自定义的扩展,你不能只用'for-each'本身吗? – 2014-10-02 13:34:11

+0

这是因为在我们的应用程序(http://www.skipper18.com)中使用了非常复杂的转换,部分XSLT函数已被C代码重写。现在,重写也是在输入XML中查找数据的函数也很方便。因此,不要与saxon一起串接字符串:例如,执行我们自己的<...>。很难用几句话来形容,但希望它是可以理解的。 – 2014-10-02 13:50:26

回答

1

有可能戳成传递到您的变换函数的上下文对象修改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; 
} 

您还可能需要保存和恢复一些其他上下文变量。看看xsltForEach in libxslt/transform.c内部如何实现libxsltfor-each

+0

感谢您的回复。我会尽快尝试。 – 2015-01-03 19:56:02

+0

嗨,再次感谢您的回复。今天我终于有一些时间来检查它并尝试它。我将最终解决方案作为独立回复发布。你的建议非常有帮助。只需稍加注意,如果不使用内部xpath查询,则不需要存储上下文。 – 2015-04-03 20:24:55

0

基于@nwellnholf的建议我检查了transform.c,过了一段时间后我想出了如何实现它。

@nwellnholf写道,核心魔法在xsltApplySequenceConstructor之内。为了能够使用它,有必要编辑库并公开这个函数,因为最初这个函数仅在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); 
} 
相关问题