MDA之路

MDA,UML,XML,Eclipse及Java相关的Blog
posts - 53, comments - 494, trackbacks - 0, articles - 2
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

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

Posted on 2006-03-08 22:52 wxb_nudt 阅读(7843) 评论(4)  编辑  收藏 所属分类: 技术杂谈

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属性相加等于PublicationnbPages属性;

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

由于之前我并没有接触过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不包含forwhile等循环语句。当简单的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,它带有三个参数strindex nodenum,分别表示连接的字符串、迭代子和chapters的节点数。通过这种方法,熟悉递归的人可以很快的写出几乎和javascript等价的种种数据操作。当然,由于变量不能赋值、参数只能以递归的方式来改动,还是很不方便的。

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

3.     小结

深入讲解XSLT的中文文献不多,大多数是入门级的。当我半猜半试的解决了这个问题后。发现了在O’Reilly有一本《XSLT》的书,其中列出了这样的内容。
       哦,今天是女孩节,祝我的乖老婆和乖乖女儿节日快乐,身体健康啦!
既然这么高兴,就贴一张刚刚照的雯雯百日照好了。
11.JPG


评论

# re: 一个XSLT的变量、参数和模板调用的问题  回复  更多评论   

2006-03-10 16:06 by NetFetch
既然结合Xpath来实现他,我看是否可以简化一些?

# re: 一个XSLT的变量、参数和模板调用的问题  回复  更多评论   

2007-06-27 16:59 by zhangcd
文章写的好!宝宝很可爱!谢谢!

# re: 一个XSLT的变量、参数和模板调用的问题  回复  更多评论   

2008-04-22 12:54 by 54by
刚开始学XSLT, 试试


<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="Book">
<xsl:element name="Publication">
<xsl:attribute name="title" select="@title"/>
<xsl:attribute name="nbPages" select="sum(chapters/@nbPages)"/>
<xsl:apply-templates select="chapters[1]"/>
</xsl:element>
</xsl:template>
<xsl:template match="chapters">
<xsl:param name="str"/>
<xsl:choose>
<xsl:when test="not(following-sibling::*)">
<xsl:attribute name="authors" select="substring(concat($str,' and ',@author),6)"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="following-sibling::chapters[1]">
<xsl:with-param name="str" select="concat($str,' and ',@author)"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

# re: 一个XSLT的变量、参数和模板调用的问题[未登录]  回复  更多评论   

2008-12-09 19:42 by gordon
好东西,多谢分享

只有注册用户登录后才能发表评论。


网站导航: