2010-06-18 28 views
0

這是我設計的例子,它說明了我正在嘗試完成的事情。我有一個輸入XML文件,我希望將其進一步處理。重用XSL模板以用不同的相對XPath調用

輸入文件:

<BICYCLES> 
    <BICYCLE> 
     <COLOR>BLUE</COLOR> 
     <WHEELS> 
      <WHEEL> 
       <WHEEL_TYPE>FRONT</WHEEL_TYPE> 
       <FLAT>NO</FLAT> 
       <REFLECTORS> 
        <REFLECTOR> 
         <REFLECTOR_NUM>1</REFLECTOR_NUM> 
         <SHAPE>SQUARE</SHAPE> 
        </REFLECTOR> 
        <REFLECTOR> 
         <REFLECTOR_NUM>2</REFLECTOR_NUM> 
         <SHAPE>ROUND</SHAPE> 
        </REFLECTOR> 
       </REFLECTORS> 
      </WHEEL> 
      <WHEEL> 
       <WHEEL_TYPE>REAR</WHEEL_TYPE> 
       <FLAT>NO</FLAT> 
      </WHEEL> 
     </WHEELS> 
    </BICYCLE> 
</BICYCLES> 

輸入是<BICYCLE>節點的列表。每個<BICYCLE>具有<COLOR>並且可選地具有<WHEELS>

<WHEELS>是一個<WHEEL>節點的列表,每個節點有幾個屬性,並且可選地具有<REFLECTORS>

<REFLECTORS><REFLECTOR>節點的列表,每個節點都有幾個屬性。

目標是平坦化這個XML。這是我使用的XSL:

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

<xsl:template match="/"> 
<BICYCLES> 
<xsl:apply-templates/> 
</BICYCLES> 
</xsl:template> 

<xsl:template match="BICYCLE"> 
<xsl:choose> 
    <xsl:when test="WHEELS"> 
     <xsl:apply-templates select="WHEELS"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <BICYCLE> 
      <COLOR><xsl:value-of select="COLOR"/></COLOR> 
      <WHEEL_TYPE/> 
      <FLAT/> 
      <REFLECTOR_NUM/> 
      <SHAPE/> 
     </BICYCLE> 
    </xsl:otherwise> 
</xsl:choose> 
</xsl:template> 

<xsl:template match="WHEELS"> 
<xsl:apply-templates select="WHEEL"/> 
</xsl:template> 

<xsl:template match="WHEEL"> 
    <xsl:choose> 
     <xsl:when test="REFLECTORS"> 
      <xsl:apply-templates select="REFLECTORS"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <BICYCLE> 
       <COLOR><xsl:value-of select="../../COLOR"/></COLOR> 
       <WHEEL_TYPE><xsl:value-of select="WHEEL_TYPE"/></WHEEL_TYPE> 
       <FLAT><xsl:value-of select="FLAT"/></FLAT> 
       <REFLECTOR_NUM/> 
       <SHAPE/> 
      </BICYCLE> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template match="REFLECTORS"> 
    <xsl:apply-templates select="REFLECTOR"/> 
</xsl:template> 

<xsl:template match="REFLECTOR"> 
    <BICYCLE> 
     <COLOR><xsl:value-of select="../../../../COLOR"/></COLOR> 
     <WHEEL_TYPE><xsl:value-of select="../../WHEEL_TYPE"/></WHEEL_TYPE> 
     <FLAT><xsl:value-of select="../../FLAT"/></FLAT> 
     <REFLECTOR_NUM><xsl:value-of select="REFLECTOR_NUM"/></REFLECTOR_NUM> 
     <SHAPE><xsl:value-of select="SHAPE"/></SHAPE> 
    </BICYCLE> 
</xsl:template> 

</xsl:stylesheet> 

輸出是:

<BICYCLES xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <BICYCLE> 
     <COLOR>BLUE</COLOR> 
     <WHEEL_TYPE>FRONT</WHEEL_TYPE> 
     <FLAT>NO</FLAT> 
     <REFLECTOR_NUM>1</REFLECTOR_NUM> 
     <SHAPE>SQUARE</SHAPE> 
    </BICYCLE> 
    <BICYCLE> 
     <COLOR>BLUE</COLOR> 
     <WHEEL_TYPE>FRONT</WHEEL_TYPE> 
     <FLAT>NO</FLAT> 
     <REFLECTOR_NUM>2</REFLECTOR_NUM> 
     <SHAPE>ROUND</SHAPE> 
    </BICYCLE> 
    <BICYCLE> 
     <COLOR>BLUE</COLOR> 
     <WHEEL_TYPE>REAR</WHEEL_TYPE> 
     <FLAT>NO</FLAT> 
     <REFLECTOR_NUM/> 
     <SHAPE/> 
    </BICYCLE> 
</BICYCLES> 

我不喜歡這是我在幾種形式輸出的顏色屬性:

<COLOR><xsl:value-of select="../../../../COLOR"/></COLOR> 
<COLOR><xsl:value-of select="../../COLOR"/></COLOR> 
<COLOR><xsl:value-of select="COLOR"/></COLOR> 
<COLOR/> 

似乎應該有一種方法來製作一個命名模板,並從需要的地方調用它,並將表示路徑的參數傳遞迴到<BICYCLE>節點它指的是。

有沒有一種方法可以清理這個問題,比如用自行車領域的命名模板,輪子領域和反射器領域?

在現實世界的例子中,除了顏色之外,還有更多屬性指向「自行車」,我想讓這個XSL易於更改以包含或排除字段,而無需更改XSL多個地方。

回答

2

您可以使用name屬性命名模板。您使用<xsl:call-template>按名稱調用模板,並且它的有效(IIRC)<xsl:apply-templates>有效。

更新(來自評論):聽起來像你想要一個不同的axis,可能ancestor。像ancestor::bicycle/color

+0

但是路徑在模板中?如果我放入,如果從REFECTOR模板調用模板,它將不會找到該顏色。 – user189169 2010-06-18 16:06:32

+1

@meomaxy聽起來你想要一個不同的[axis](http://www.w3schools.com/xpath/xpath_axes.asp),可能是'ancestor'。像「祖先::自行車/顏色」? – 2010-06-18 16:22:09

+0

是的!祖先或自己::自行車/彩色謝謝! – user189169 2010-06-18 16:38:46

0

你的意思是這樣的:

<xsl:template name="wheelblock"> 
    <xsl:param name="color"></xsl:param> 
    <!-- Do something here --> 
</xsl:template> 

<xsl:template match="WHEEL"> 
    <xsl:call-template name="wheelblock"> 
    <xsl:with-param name="color">whatever element/etc</xsl:with-param> 
    </xsl:call-template> 
</xsl:template> 
+0

不,我不想讓顏色成爲參數,我想讓BICYCLE節點的路徑成爲參數,這樣我就可以編寫一個可以找到自行車顏色的模板,不管它是從BICYCLE調用的, WHEEL或REFLECTOR模板。如果模板可以自行返回以找到正確的節點,那麼好多了,但至少呼叫者知道正確的路徑。 – user189169 2010-06-18 16:11:36

2

我不喜歡這個是什麼 我在輸出幾個 形式的顏色屬性:

這 好像,就必須有一種方式來 進行命名模板並調用它從不同的地方,它是 需要 和傳遞一些參數,即 表示返回到它所指向的 節點的路徑。

有沒有辦法清理這個,說 與自行車 領域,爲輪子領域和爲 反射器領域的命名模板?

您可以實現更多的再利用比這個

原理是爲了避免條件邏輯,並讓XSLT處理器選擇要處理的模板。任何需要的值都應作爲參數傳遞到應用模板。

下轉變表明了這些原則

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="BICYCLE"> 
    <xsl:apply-templates> 
    <xsl:with-param name="pColor" select="COLOR"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="BICYCLE[not(WHEELS)]"> 
    <BICYCLE> 
     <COLOR><xsl:value-of select="COLOR"/></COLOR> 
     <WHEEL_TYPE/> 
     <FLAT/> 
     <REFLECTOR_NUM/> 
     <COLOR/> 
     <SHAPE/> 
    </BICYCLE> 
</xsl:template> 

<xsl:template match="WHEELS"> 
    <xsl:param name="pColor"/> 

    <xsl:apply-templates> 
    <xsl:with-param name="pColor" select="$pColor"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="WHEEL[REFLECTORS]"> 
    <xsl:param name="pColor"/> 

    <xsl:apply-templates select="REFLECTORS"> 
    <xsl:with-param name="pColor" select="$pColor"/> 
    <xsl:with-param name="pWheel_Type" select="WHEEL_TYPE"/> 
    <xsl:with-param name="pFlat" select="FLAT"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="WHEEL"> 
    <xsl:param name="pColor"/> 

    <BICYCLE> 
     <COLOR><xsl:value-of select="$pColor"/></COLOR> 
     <WHEEL_TYPE><xsl:value-of select="WHEEL_TYPE"/></WHEEL_TYPE> 
     <FLAT><xsl:value-of select="FLAT"/></FLAT> 
     <REFLECTOR_NUM/> 
     <COLOR/> 
     <SHAPE/> 
    </BICYCLE> 
</xsl:template> 

<xsl:template match="REFLECTORS"> 
    <xsl:param name="pColor"/> 
    <xsl:param name="pWheel_Type"/> 
    <xsl:param name="pFlat"/> 

    <xsl:apply-templates select="REFLECTOR"> 
    <xsl:with-param name="pColor" select="$pColor"/> 
    <xsl:with-param name="pWheel_Type" select="$pWheel_Type"/> 
    <xsl:with-param name="pFlat" select="$pFlat"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="REFLECTOR"> 
    <xsl:param name="pColor"/> 
    <xsl:param name="pWheel_Type"/> 
    <xsl:param name="pFlat"/> 

    <BICYCLE> 
     <COLOR><xsl:value-of select="$pColor"/></COLOR> 
     <WHEEL_TYPE><xsl:value-of select="$pWheel_Type"/></WHEEL_TYPE> 
     <FLAT><xsl:value-of select="$pFlat"/></FLAT> 
     <REFLECTOR_NUM><xsl:value-of select="REFLECTOR_NUM"/></REFLECTOR_NUM> 
     <COLOR><xsl:value-of select="COLOR"/></COLOR> 
     <SHAPE><xsl:value-of select="SHAPE"/></SHAPE> 
    </BICYCLE> 
</xsl:template> 

<xsl:template match="BICYCLE/COLOR"/> 
</xsl:stylesheet> 

當所提供的XML文檔應用,想要的結果產生

<BICYCLES> 
<BICYCLE> 
    <COLOR>BLUE</COLOR> 
    <WHEEL_TYPE>FRONT</WHEEL_TYPE> 
    <FLAT>NO</FLAT> 
    <REFLECTOR_NUM>1</REFLECTOR_NUM> 
    <COLOR>RED</COLOR> 
    <SHAPE>SQUARE</SHAPE> 
</BICYCLE> 
<BICYCLE> 
    <COLOR>BLUE</COLOR> 
    <WHEEL_TYPE>FRONT</WHEEL_TYPE> 
    <FLAT>NO</FLAT> 
    <REFLECTOR_NUM>2</REFLECTOR_NUM> 
    <COLOR>WHITE</COLOR> 
    <SHAPE>ROUND</SHAPE> 
</BICYCLE> 
<BICYCLE> 
    <COLOR>BLUE</COLOR> 
    <WHEEL_TYPE>REAR</WHEEL_TYPE> 
    <FLAT>NO</FLAT> 
    <REFLECTOR_NUM/> 
    <COLOR/> 
    <SHAPE/> 
</BICYCLE> 
</BICYCLES> 
0

感謝漢克同性戀!這是我正在尋找的。以下XSL與我的原始輸出相同:

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

<xsl:template name="allfields"> 
    <BICYCLE> 
     <COLOR><xsl:value-of select="ancestor-or-self::BICYCLE/COLOR"/></COLOR> 
     <WHEEL_TYPE><xsl:value-of select="ancestor-or-self::WHEEL/WHEEL_TYPE"/></WHEEL_TYPE> 
     <FLAT><xsl:value-of select="ancestor-or-self::WHEEL/FLAT"/></FLAT> 
     <REFLECTOR_NUM><xsl:value-of select="ancestor-or-self::REFLECTOR/REFLECTOR_NUM"/></REFLECTOR_NUM> 
     <SHAPE><xsl:value-of select="ancestor-or-self::REFLECTOR/SHAPE"/></SHAPE> 
    </BICYCLE> 
</xsl:template> 

<xsl:template match="/"> 
<BICYCLES> 
    <xsl:apply-templates/> 
</BICYCLES> 
</xsl:template> 

<xsl:template match="BICYCLE"> 
<xsl:choose> 
    <xsl:when test="WHEELS"> 
     <xsl:apply-templates/> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:call-template name="allfields"/> 
    </xsl:otherwise> 
</xsl:choose> 
</xsl:template> 

<xsl:template match="WHEEL"> 
      <xsl:apply-templates/> 
    <xsl:choose> 
     <xsl:when test="REFLECTORS"> 
      <xsl:apply-templates/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:call-template name="allfields"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template match="REFLECTOR"> 
    <xsl:call-template name="allfields"/> 
</xsl:template> 

</xsl:stylesheet> 
+0

這比將必要的參數傳遞給模板效率更低。 '祖先:'軸將不得不被掃描多次。我的答案沒有這樣的低效率。另一個觀察結果是,您可以通過刪除條件處理(''和'')來簡化代碼,並將此工作留給XSLT處理器。總而言之,這個代碼有很大的改進空間。 – 2010-06-18 20:41:24

0

兩種方式。

保留您ancestor-or-self軸的使用:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:template match="/"> 
    <BICYCLES> 
     <xsl:for-each select="BICYCLE[not(WHELLS)]|//REFLECTOR|//WHEEL[not(REFLECTORS)]"> 
      <BICYCLE> 
       <COLOR><xsl:value-of select="ancestor-or-self::BICYCLE/COLOR"/></COLOR> 
       <WHEEL_TYPE><xsl:value-of select="ancestor-or-self::WHEEL/WHEEL_TYPE"/></WHEEL_TYPE> 
       <FLAT><xsl:value-of select="ancestor-or-self::WHEEL/FLAT"/></FLAT> 
       <REFLECTOR_NUM><xsl:value-of select="ancestor-or-self::REFLECTOR/REFLECTOR_NUM"/></REFLECTOR_NUM> 
       <COLOR><xsl:value-of select="ancestor-or-self::REFLECTOR/COLOR"/></COLOR> 
       <SHAPE><xsl:value-of select="ancestor-or-self::REFLECTOR/SHAPE"/></SHAPE> 
      </BICYCLE> 
     </xsl:for-each> 
    </BICYCLES> 
</xsl:template> 

</xsl:stylesheet> 

這僅僅是一個規則的處理模型的濫用的例子。

相比之下,使用Dimitre後,您可以避免相關邏輯,並將模板應用於所需的分支。

我認爲在這種情況下,後代和祖先軸對於長XML輸入來說效率不高。所以,如果你進一步處理空節點,而不是現有的節點是相同的(就像數據庫結果),這個一般模式應該工作:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output indent="yes" method="xml"/> 

    <xsl:template match="/"> 
     <BICYCLES> 
      <xsl:apply-templates/> 
     </BICYCLES> 
    </xsl:template> 

    <!-- 
     When you don't want a leaf in your result, just: 
     <xsl:template match="here the leaf name" /> 
    --> 

    <xsl:template match="*"> 
     <xsl:copy> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*[*/*]"> 
     <xsl:param name="prev" /> 
     <xsl:apply-templates select="*[*]"> 
      <xsl:with-param name="prev"> 
       <xsl:copy-of select="$prev"/> 
       <xsl:apply-templates select="*[not(*)]"/> 
      </xsl:with-param> 
     </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="*[* and not(*/*)]"> 
     <xsl:param name="prev" /> 
     <BICYCLE> 
      <xsl:copy-of select="$prev"/> 
      <xsl:apply-templates select="*"/> 
     </BICYCLE> 
    </xsl:template> 

</xsl:stylesheet> 

注意:你不必知道至極的葉子。

編輯:使用後代和祖先軸的糟糕例子,一些調整我的建議

EDIT2:添加一個新的更多鈔票葉(我錯過了第一次!)壞實施。增加排除一些葉子的可能性以便第二次執行。

編輯3:只是重寫來澄清我的觀點。

+0

謝謝!對於第一個實現,假設總是有一個輪子,匹配=「REFLECTOR | WHEEL [not(REFLECTORS)]」>>我不希望它跳過沒有車輪的自行車。關於第二,在我的情況下,我實際上不想輸出所有的葉子,我只想輸出我指定的葉子,但這是非常有幫助的。謝謝。 – user189169 2010-06-18 18:31:20

+0

@meomaxy:第一個實現是最糟糕的!如果你不得不重新使用它,你需要弄清楚葉子是什麼(在這種情況下,每個REFLECTOR都定義了一種自行車,即使它沒有反射鏡,也是任何一種輪子)。關於第二個實施,我會編輯它以便輕鬆獲取您的要求。 – 2010-06-18 18:52:10

相關問題