2010-12-16 78 views
1

平臺:撒克遜9 - XSLT 2.0排序XML元素順序XSLT基於在外部文檔指定的順序

我有需要定期編輯,更新和保存3000個的XML文檔。

該過程的一部分包括在編輯之前從存儲庫中檢出文檔,並在編輯完成後定期發佈它。

每個文檔包含一系列單獨命名的部分,例如,

<part> 
     <meta> 
      <place_id>12345</place_id> 
      <place_name>London</place_name> 
      <country_id>GB</country_id> 
      <country_name>United Kingdom</country_name> 
     </meta> 
     <text> 
      <docs>some blurb</docs> 
      <airport>some blurb LGW LHR</airport> 
      <trains>some blurb</trains> 
      <hotels>some blurb</hotels> 
      <health>some blurb</health> 
      <attractions>some blurb</attractions> 
     </text> 
    </part> 

在文本元素有近100部,並與所有的編輯團隊,他們改變主意的優先順序上偶爾,但經常,基礎。也許每年兩次。

目前,我們向當前首選編輯中的編輯提供XML文檔部分以進行編輯和發佈。這個順序被稱爲「stdhdg.xml」動態產生的外部文檔中指定,並且出現這樣的事:

<hdgs> 
    <hdg name="docs" newsort="10"/> 
    <hdg name="airport" newsort="30"/> 
    <hdg name="trains" newsort="20"/> 
    <hdg name="hotels" newsort="40"/> 
    <hdg name="health" newsort="60"/> 
    <hdg name="attractions" newsort="50"/> 
</hdgs> 

,其中,通過熱浸鍍鋅/ @ newsort規定的優選排序次序。

於是我就用一個模板像這樣以正確的順序

<xsl:template match="text"> 
    <xsl:variable name="thetext" select="."/> 
<xsl:variable name="stdhead" select="document('stdhdg.xml')"/> 
    <text> 
     <xsl:for-each select="$stdhead//hdg"> 
      <xsl:sort data-type="number" order="ascending" select="@newsort"/> 
      <xsl:variable name="tagname" select="@name"/> 
      <xsl:variable name="thisnode" select="$thetext/*[local-name() = $tagname]"/> 
      <xsl:apply-templates select="$thisnode"/> 
     </xsl:for-each> 
    </text> 
</xsl:template> 

到過程,但它似乎非常緩慢和繁瑣的,我覺得我應該使用鍵加速這一過程。

是否有一個簡單/整潔的方式來做這個排序操作。

(請不要問我的方式來改變編輯的編輯,這是比我的生命更有價值)

TIA

Feargal

+0

好問題,+1。請參閱我的答案,以獲得完全消除每次編輯之前重新排序的解決方案。 :) – 2010-12-16 15:43:21

回答

0

是,鑰匙要加快這種查找。這裏是一個概要:

<xsl:stylesheet ...> 

    <xsl:key name="k1" match="text/*" use="local-name()"/> 

    <xsl:variable name="stdhead" select="document('stdhdg.xml')"/> 

    ... 

<xsl:template match="text"> 
    <xsl:variable name="thetext" select="."/> 
    <text> 
     <xsl:for-each select="$stdhead//hdg"> 
      <xsl:sort data-type="number" order="ascending" select="@newsort"/> 
      <xsl:apply-templates select="key('k1', @name, $thetext)"/> 
     </xsl:for-each> 
    </text> 
</xsl:template> 

</xsl:stylesheet> 

所有直接在瀏覽器中輸入,所以把它作爲大綱如何接近它,而不是在測試代碼。

[編輯]作爲第二個想法,我覺得每次處理一個text元素是一種浪費時間的排序,所以你可以改變

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

    <xsl:key name="k1" match="text/*" use="local-name()"/> 

    <xsl:variable name="stdhead" select="document('stdhdg.xml')"/> 

    <xsl:variable name="sorted-headers" as="element(hdg)*"> 
    <xsl:perform-sort select="$stdhead//hdg"> 
     <xsl:sort select="@newsort" data-type="number"/> 
    </xsl:perform-sort> 
    </xsl:variable> 

<xsl:template match="text"> 
    <xsl:variable name="thetext" select="."/> 
    <text> 
     <xsl:for-each select="$sorted-headers"> 
      <xsl:apply-templates select="key('k1', @name, $thetext)"/> 
     </xsl:for-each> 
    </text> 
</xsl:template> 

</xsl:stylesheet> 
+0

+1對於'xsl:perform-sort'示例。我懷疑即使對於大型文檔這個關鍵用法(選擇上下文節點子節點),它也會加快進程的速度,這會使您忘記內存成本。 – 2010-12-16 12:58:22

+0

@Alejandro:你可能有興趣閱讀我的答案,夥計們。 :) – 2010-12-16 15:44:13

0

在文本元素有 近100節,並且與所有 編輯團隊一樣,他們偶爾會根據首選訂單 更改 。也許 每年兩次。

。 。 。 。 。 。

但它似乎很 緩慢和繁瑣,我覺得我 應該使用鍵來加快它

當它被提出來編輯每次排序的文件是錯誤的做法

最好的解決方案是對它進行排序並保存,每年僅排序2次當'stdhdg.xml'文檔發生更改時。

如果「stdhdg.xml」的變化不能被組織上同步的很好,你可以運行下面的轉型重複(比如每天)工作:

<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:param name="vHeaderLoc" select="'file:///C:/temp/deleteMe/stdhdg.xml'"/> 

<xsl:variable name="vHeaderDoc" select= 
"document($vHeaderLoc)"/> 

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

<xsl:template match= 
    "part/@hash 
      [not(. 
       = 
       string(document('file:///C:/temp/deleteMe/stdhdg.xml')) 
      ) 
      ]"> 
    <xsl:attribute name="hash"> 
    <xsl:value-of select="string($vHeaderDoc)"/> 
    </xsl:attribute> 
</xsl:template> 

<xsl:template match= 
    "/*/text[not(/*/@hash 
       = string(document('file:///C:/temp/deleteMe/stdhdg.xml')) 
       ) 
      ]"> 
    <text> 
    <xsl:apply-templates select="*"> 
    <xsl:sort data-type="number" 
    select="$vHeaderDoc/*/hdg[@name=name(current())]"/> 
    </xsl:apply-templates> 
    </text> 
</xsl:template> 
</xsl:stylesheet> 

當主要內容的XML文檔(注意頂部元素現在有一個hash屬性)是:

<part hash="010203040506"> 
    <meta> 
     <place_id>12345</place_id> 
     <place_name>London</place_name> 
     <country_id>GB</country_id> 
     <country_name>United Kingdom</country_name> 
    </meta> 
    <text> 
     <docs>some blurb</docs> 
     <airport>some blurb LGW LHR</airport> 
     <trains>some blurb</trains> 
     <hotels>some blurb</hotels> 
     <health>some blurb</health> 
     <attractions>some blurb</attractions> 
    </text> 
</part> 

和stdhdg.xml文件

<hdgs> 
    <hdg name="docs">10</hdg> 
    <hdg name="airport">30</hdg> 
    <hdg name="trains">20</hdg> 
    <hdg name="hotels">40</hdg> 
    <hdg name="health">60</hdg> 
    <hdg name="attractions">50</hdg> 
</hdgs> 

然後改造上面產生具有最新的散列新排序的主要內容:

<part hash="103020406050"> 
    <meta> 
     <place_id>12345</place_id> 
     <place_name>London</place_name> 
     <country_id>GB</country_id> 
     <country_name>United Kingdom</country_name> 
    </meta> 
    <text> 
     <docs>some blurb</docs> 
     <trains>some blurb</trains> 
     <airport>some blurb LGW LHR</airport> 
     <hotels>some blurb</hotels> 
     <attractions>some blurb</attractions> 
     <health>some blurb</health> 
    </text> 
</part> 

請注意

  1. 主要內容文檔的頂級元素現在有一個hash屬性,其值是駐留在stdhdg.xml文檔中的排序鍵的串聯。

  2. stdhdg.xml文件的格式也稍作更改,以便可以輕鬆地將鍵的連接生成爲文檔的字符串值。

  3. 如果保存在主內容中的哈希與stdhdg.xml中的sort-keys-concatenation相同,則日常運行轉換是標識轉換。

  4. 如果舊散列與stdhdg.xml中的排序鍵不匹配,那麼它將更新爲新散列,並且節將被重新排序。