一个XSLT的变量、参数和模板调用的问题

1.     问题

昨天遇到了这样一个xml文档,如下:bookObject.xml

<?xml version="1.0" encoding="ASCII"?>

<?xml-stylesheet type="text/xsl" href="Book2PubXSLT.xsl"?>

<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI">

<Book title="WxbBook">

           <chapters nbPages="12" title="chapter1" author="author1"/>

           <chapters nbPages="15" title="chapter2" author="author2"/>

           <chapters nbPages="20" title="chapter3" author="author3"/>

</Book>

<Book title="nextBook">

           <chapters nbPages="10" title="chapter1" author="aaa"/>

           <chapters nbPages="20" title="chapter2" author="bbb"/>

           <chapters nbPages="30" title="chapter3" author="ccc"/>

</Book>

</xmi:XMI>

希望能够使用XSLT转换为这样的一个xml文档(目的是为了做一个很简单的模型转换实例,当然这点和本文主题几乎无关):publicationObject.xml

<?xml version="1.0" encoding="ASCII"?>

<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="Publication">

<Publication title="nextBook" nbPages="60" authors="ccc and aaa and bbb"/>

<Publication title="WxbBook" nbPages="47" authors="author3 and author1 and author2"/>

</xmi:XMI>

分析这两个文档可以看出,希望的转换规则如下:

Book节点有一个属性title,它等于Publication的节点属性title。

Book节点包含chapters子节点,每个子节点都有三个属性。其中一个Book节点的所有chapters子节点的nbPages属性相加等于Publication的nbPages属性;

一个Book节点的所有chapters子节点的author相连,并在中间插入and则等于Publication的authors属性。

由于之前我并没有接触过XSLT的变量、参数和xsl:call-template等概念,所以还是颇费了一点时间来解决此问题。

2.     问题的解决

值得注意的有几点:

1.              XSLT中的变量一次赋值后是不能改变的,所以这里的变量几乎等于其它语言中的常量。

2.              template有两种,常见的是通过<xsl:template match="/">这样的方式定义的,使用match属性。调用的时候是使用<xsl:apply-templates select=""/>。另一种template类似与其它语言中的函数调用,使用<xsl:template name=”t_name”>来定义,调用的时候使用<xsl:call-template name=" t_name "/>来调用。

3.              在第二种template的定义中可以加入参数,类似于其它编程语言中的参数列表。在调用时也可以传入具体的值做为实参。

4.              由于XSLT不包含for、while等循环语句。当简单的for-each不能满足要求时。则需要使用递归template调用来完成其它语言中的循环。从functional programming的理论中我们知道这二者是等价的。

下面是进行转换的XSL文档:Book2PubXSLT.xsl

<?xml version="1.0" encoding="ASCII"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:xmi="http://www.omg.org/XMI">

<xsl:template name="left">

<xsl:text disable-output-escaping="yes">&lt;</xsl:text>

</xsl:template>

<xsl:template name="right">

<xsl:text disable-output-escaping="yes">&gt;</xsl:text>

</xsl:template>

 

<xsl:template match="/">

<xsl:call-template name="left"/>xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="Publication"<xsl:call-template name="right"/>

           <xsl:apply-templates select="xmi:XMI"/>

           <xsl:call-template name="left"/>/xmi:XMI<xsl:call-template name="right"/>

</xsl:template>

 

<xsl:template match="xmi:XMI">

           <xsl:for-each select="Book">

           <xsl:call-template name="left"/>Publication title="<xsl:value-of select="@title"/>"

                           nbPages ="<xsl:value-of select="sum(chapters/@nbPages)"/>"

              authors ="

                    <xsl:call-template name="concatAuthor">

                             <xsl:with-param name="str" select="chapters/@author"/>

                             <xsl:with-param name="index" select="1"/>

                             <xsl:with-param name="nodenum" select="last()+1"/>

                    </xsl:call-template>"/<xsl:call-template name="right"/>

           </xsl:for-each>

</xsl:template>

 

<xsl:template name="concatAuthor">

           <xsl:param name="str"/>

           <xsl:param name="index"/>

           <xsl:param name="nodenum"/>

           <xsl:choose>

                    <xsl:when test="index!=nodenum">

                             <xsl:call-template name="concatAuthor">

                                       <xsl:with-param name="str" select="concat(str,and,chapters[index+1]/@author)"/>

                                       <xsl:with-param name="index" select="$index + 1"/>

                                       <xsl:with-param name="nodenum" select="$nodenum"/>

                             </xsl:call-template>

                    </xsl:when>

                    <xsl:otherwise>

                             <xsl:value-of select="$str"/>

                    </xsl:otherwise>

           </xsl:choose>

</xsl:template>

</xsl:stylesheet>

从上面可以看出,解决问题最主要的一点就是使用了一个递归模板concatAuthor,它带有三个参数str,index 和nodenum,分别表示连接的字符串、迭代子和chapters的节点数。通过这种方法,熟悉递归的人可以很快的写出几乎和javascript等价的种种数据操作。当然,由于变量不能赋值、参数只能以递归的方式来改动,还是很不方便的。

其优点也是明显的,不依赖其它脚本语言完成了数据操作。可以在所有xsl引擎上面运行。

3.     小结

深入讲解XSLT的中文文献不多,大多数是入门级的。当我半猜半试的解决了这个问题后。发现了在O’Reilly有一本《XSLT》的书,其中列出了这样的内容。

出处:http://www.blogjava.net/wxb_nudt/archive/2006/03/08/34377.html

posted on   jack_Meng  阅读(2392)  评论(0编辑  收藏  举报

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?

导航

< 2012年7月 >
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 1 2 3 4
5 6 7 8 9 10 11
点击右上角即可分享
微信分享提示

喜欢请打赏

扫描二维码打赏

支付宝打赏

主题色彩