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 閱讀(7863) 評論(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
          好東西,多謝分享
          主站蜘蛛池模板: 桃江县| 芦山县| 建昌县| 上杭县| 泸定县| 大城县| 南安市| 平阴县| 汝城县| 龙口市| 祁阳县| 鹤峰县| 犍为县| 荥阳市| 高密市| 额济纳旗| 满洲里市| 大同县| 靖州| 三穗县| 祥云县| 嘉祥县| 讷河市| 盐亭县| 赫章县| 阿巴嘎旗| 大姚县| 库伦旗| 兴安县| 阳城县| 东阿县| 元阳县| 汉沽区| 连城县| 花垣县| 定日县| 拜城县| 临西县| 通化市| 太原市| 山西省|