2011-07-08 92 views
3

第一個小背景:我使用集合管理軟件GCStar來管理我的數字圖書館(漫畫/漫畫/電影,你的名字 - 除了書籍以外,它非常棒)。問題是,它不能讓我按多個鍵對貨架進行分類,例如按照Series和Episode號碼排序。隨後添加的劇集總是會在系列中顯示較低的內容。按屬性排序XML並修改

我對這些配置進行了修改,發現它使用的.gcs文件只不過是一種XML(我只是非常熟悉)。像這樣:

<?xml version="1.0" encoding="UTF-8"?> 
<collection type="GCTVepisodes" items="101" version="1.6.1"> 
<information> 
    <maxId>101</maxId> 
</information> 

<item 
    id="1" 
    name="The Vice President Doesn't Say Anything about the Possibility of 
     Him Being the Main Character" 
    series="Baccano" 
    season="1" 
    episode="1" 
    ... 
> 
    <synopsis>It's 1931 and...</synopsis> 
... 
</item> 
<item ... 

該程序,據我所知,總是按照ID降序(每當我添加一集時增加)。所以,我需要在這當中,將會以變換:

  1. 排序XML的系列,那麼賽季,然後插曲
  2. 更改ID相應的屬性,從1開始到結束(也復位基於該maxId)
  3. 將其全部寫入到另一個XML的相同格式。

如何做到這一點(顯然不是在說這裏的切割代碼)? XSLT可以完成所有這些工作嗎?我應該看看Perl中基於樹的解析器嗎?這是週末,我在一臺Linux機器上,所以在UNIX上運行的開源解決方案會很好 - 在Perl中的某些東西可能是最好的。我應該讀什麼?

如果我在家裏不能這樣做,那麼我總是可以在辦公室設計一個小型數據存儲工作,但我真的很喜歡更簡單的解決方案。

謝謝! :)

+0

好的,所以我完成了,人們...... :-D一開始並沒有我所希望的那麼容易。必須在幾個地方修補GCStar代碼(其他人已經完成了音樂模型的努力工作,很容易調整它並適用於電視節目模型)。現在程序按id排序,並且程序啓動腳本中的一些變化可以確保我總是運行XSLT,以便ID保持良好狀態。 –

+0

對於這個問題。看到我的答案,知道如何使用兩個簡單的模板來獲得想要的結果。 –

回答

2

maxId(和集合中的項目)值不應更改,因爲您不刪除或添加ID。

如果您想要一個簡單的命令行開源XSLT轉換器,請使用libxml2/libxslt中的XSLTProc。它幾乎可以在任何標準的linux上使用。 http://xmlsoft.org/XSLT/xsltproc2.html

使用此命令xsltproc transform.xsl input.xml >output.xml

這裏是一個解決方案,XSLT轉換樣式表,應該工作;-)(我有足夠的空閒時間來編寫它)

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:output method="xml" encoding="UTF-8" indent="yes"/> 

<xsl:strip-space elements="*"/> 

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

<!-- remove items, they will be sorted and inserted later --> 
<xsl:template match="/collection/item"/> 

<!-- remove id --> 
<xsl:template match="/collection/item/@id"/> 

<xsl:template match="/collection"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     <!-- copy and sort item by series, then season, then episode --> 
     <xsl:for-each select="item"> 
      <xsl:sort select="@series" data-type="text"/> 
      <xsl:sort select="@season" data-type="number"/> 
      <xsl:sort select="@episode" data-type="number"/> 
      <xsl:copy> 
       <xsl:attribute name="id"> 
        <xsl:value-of select="position()"/> 
       </xsl:attribute> 
       <!-- copy the rest of item --> 
       <xsl:apply-templates select="@*|node()"/> 
      </xsl:copy> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

我用這個簡化的數據來測試它:

<?xml version="1.0" encoding="UTF-8"?> 
<collection type="GCTVepisodes" items="5" version="1.6.1"> 
<information> 
    <maxId>5</maxId> 
</information> 

<item 
    id="1" 
    name="The Vice President Doesn't Say Anything about the Possibility of 
     Him Being the Main Character" 
    series="Baccano" 
    season="1" 
    episode="1"/> 

<item 
    id="2" 
    name="blabla" 
    series="c" 
    season="1" 
    episode="2"/> 

<item 
    id="3" 
    name="abc" 
    series="Baccano" 
    season="2" 
    episode="1"/> 

<item 
    id="4" 
    name="blabla2" 
    series="Baccano" 
    season="1" 
    episode="2"/> 

<item 
    id="5" 
    name="first of c" 
    series="c" 
    season="1" 
    episode="1"/> 

</collection> 

這是結果(看位置和ID如何變化):

<?xml version="1.0" encoding="UTF-8"?> 
<collection type="GCTVepisodes" items="5" version="1.6.1"> 
    <information> 
    <maxId>5</maxId> 
    </information> 
    <item id="1" name="The Vice President Doesn't Say Anything about the Possibility of Him Being the Main Character" series="Baccano" season="1" episode="1"/> 
    <item id="2" name="blabla2" series="Baccano" season="1" episode="2"/> 
    <item id="3" name="abc" series="Baccano" season="2" episode="1"/> 
    <item id="4" name="first of c" series="c" season="1" episode="1"/> 
    <item id="5" name="blabla" series="c" season="1" episode="2"/> 
</collection> 
+0

嗯,我看了看並理解它(從今天晚上開始一直在查看XSLT排序等),並且這應該起作用了......除非它不行。看起來我們需要按照數字排序,否則第1集之後是10,11,12等。我想我在某個地方看過一個DATATYPE = NUM​​BER類的東西......想法? –

+0

是的,也許它不能正常工作。我沒有用更長的數字測試它。我將編輯我的帖子並將'datatype = number'添加到正確的位置。這是一個很好的XSLT參考網站:[w3schools xsl:sort](http://www.w3schools.com/xsl/el_sort.asp) – therealmarv

+0

+1是一個很好的開始。應該足以讓他啓動他的項目。 –

0

XSLT可以完成所有這些工作嗎?

是的。通過一系列見下面

  • 排序的子答案XML,然後賽季,然後插曲

是的,你可以使用XSLT來排序XML。

http://www.w3schools.com/xsl/xsl_sort.asp

  • 更改ID相應的屬性,從1開始到結束(也復位基於該maxId)

你也可以用它來寫任何文字你想。這意味着您可以替換變換中的數據。

它也可以assign variables,做if statementsloops,做XPath查詢,有一個built-in function library,等等,所以它會比足夠強大,更適合你想要做什麼。

  • 寫了這一切到相同格式到另一種XML

...這也意味着你可以用它來寫XML

我應該讀了上?

XSLT :)

W3Schools的鏈接(以上所有環節)爲豐富我,但我已經熟悉的XML結構,一般(屬性,元素,根元素,內部文本,等等)。如果您熟悉這一點,只需閱讀XSLT。

您也可以查看XmlStarlet,這是一個設計用於從命令行或shell腳本/批處理文件查詢和轉換XML的工具(儘管對於轉換,它可能會使用XSLT)。

+0

好的......大概我可以在我的shell中使用xsltproc來執行樣式表?現在查看鏈接... –

+0

@ Deep-B:當然可以。 「xsltproc是將XSLT樣式表應用於XML文檔的命令行工具」。 http://xmlsoft.org/XSLT/xsltproc.html –

+0

@ Deep-B:您也可以使用您的瀏覽器。它們都支持大部分XSLT 1.0和XPath 1.0規範。 Webkit使用libxslt。 – Saxoier

0

我也會用XSLT來做到這一點。但是,我的樣式表與therealmarv的樣式表有點不同。

此XML輸入:

<collection type="GCTVepisodes" items="101" version="1.6.1"> 
    <information> 
    <maxId>101</maxId> 
    </information> 

    <item 
    id="1" 
    name="The Vice President Doesn't Say Anything about the Possibility of 
    Him Being the Main Character" 
    series="Baccano" 
    season="1" 
    episode="2" 
    > 
    <synopsis>Blah blah blah...</synopsis> 
    ... 
    </item> 

    <item 
    id="2" 
    name="some name" 
    series="Alpha" 
    season="2" 
    episode="1" 
    > 
    <synopsis>Blah blah blah...</synopsis> 
    ... 
    </item> 


    <item 
    id="3" 
    name="The Vice President Doesn't Say Anything about the Possibility of 
    Him Being the Main Character" 
    series="Baccano" 
    season="1" 
    episode="1" 
    > 
    <synopsis>It's 1931 and...</synopsis> 
    ... 
    </item> 

    <item 
    id="4" 
    name="some name" 
    series="Alpha" 
    season="1" 
    episode="1" 
    > 
    <synopsis>Blah blah blah...</synopsis> 
    ... 
    </item> 

</collection> 

這個樣式表:

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

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

    <xsl:template match="collection"> 
    <collection> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates select="information"/> 
     <xsl:apply-templates select="item"> 
     <xsl:sort select="@series" data-type="text"/> 
     <xsl:sort select="@season" data-type="number"/> 
     <xsl:sort select="@episode" data-type="number"/> 
     </xsl:apply-templates>  
    </collection> 
    </xsl:template> 

    <xsl:template match="item"> 
    <item id="{position()}"> 
     <xsl:apply-templates select="@*[not(name()='id')]|node()"/> 
    </item> 
    </xsl:template> 

</xsl:stylesheet> 

產生這樣的輸出:從therealmarv的答案它產生

<collection type="GCTVepisodes" items="101" version="1.6.1"> 
    <information> 
     <maxId>101</maxId> 
    </information> 
    <item id="1" name="some name" series="Alpha" season="1" episode="1"> 
     <synopsis>Blah blah blah...</synopsis> 
    ... 
    </item> 
    <item id="2" name="some name" series="Alpha" season="2" episode="1"> 
     <synopsis>Blah blah blah...</synopsis> 
    ... 
    </item> 
    <item id="3" name="The Vice President Doesn't Say Anything about the Possibility of  Him Being the Main Character" series="Baccano" season="1" episode="1"> 
     <synopsis>It's 1931 and...</synopsis> 
    ... 
    </item> 
    <item id="4" name="The Vice President Doesn't Say Anything about the Possibility of  Him Being the Main Character" series="Baccano" season="1" episode="2"> 
     <synopsis>Blah blah blah...</synopsis> 
    ... 
    </item> 
</collection> 

與輸入:

<collection type="GCTVepisodes" items="5" version="1.6.1"> 
    <information> 
     <maxId>5</maxId> 
    </information> 
    <item id="1" name="The Vice President Doesn't Say Anything about the Possibility of  Him Being the Main Character" series="Baccano" season="1" episode="1"/> 
    <item id="2" name="blabla2" series="Baccano" season="1" episode="2"/> 
    <item id="3" name="abc" series="Baccano" season="2" episode="1"/> 
    <item id="4" name="first of c" series="c" season="1" episode="1"/> 
    <item id="5" name="blabla" series="c" season="1" episode="2"/> 
</collection> 
+0

啊看起來不錯。從未在應用模板中使用過排序。似乎我可以在這裏學習一些新的東西在計算器:-) – therealmarv

+0

優秀。儘可能避免「for-each」循環。當我開始在XSLT中循環時,似乎我陷入了錯誤的思維集。 ;-) –

+0

這真的幫了我很多,非常感謝! :) –

1

你可以使用兩個簡單的模板相同的結果:

  • 在第一個模板(身份),我們可以稍稍「東方」的,以item元素排序應用模板機制。
  • 在第二模板中,我們可以覆蓋每個item元件,並使用position()函數重新計算id屬性。我們將按原樣離開其他所有後代節點,但不包括item的原始id

XSLT 1.0變換與撒克遜測試6.5.5

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

    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()[not(self::item)]"/> 
      <xsl:apply-templates select="item"> 
       <xsl:sort select="@series"/> 
       <xsl:sort select="@season" data-type="number"/> 
       <xsl:sort select="@episode" data-type="number"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="item"> 
     <item id="{position()}"> 
      <xsl:apply-templates select="@*[name()!='id']|node()"/> 
     </item> 
    </xsl:template> 

</xsl:stylesheet> 

當上述變換應用於下列輸入(@therealmarv比特修改爲包括子元素):

<collection type="GCTVepisodes" items="5" version="1.6.1"> 
    <information> 
     <maxId>5</maxId> 
    </information> 
    <item 
     id="1" 
     name="The Vice President Doesn't Say Anything about the Possibility of 
     Him Being the Main Character" 
     series="Baccano" 
     season="1" 
     episode="1"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
    <item 
     id="2" 
     name="blabla" 
     series="c" 
     season="1" 
     episode="2"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
    <item 
     id="3" 
     name="abc" 
     series="Baccano" 
     season="2" 
     episode="1"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
    <item 
     id="4" 
     name="blabla2" 
     series="Baccano" 
     season="1" 
     episode="2"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
    <item 
     id="5" 
     name="first of c" 
     series="c" 
     season="1" 
     episode="1"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
</collection> 

產生以下輸出:

<collection type="GCTVepisodes" items="5" version="1.6.1"> 
    <information> 
     <maxId>5</maxId> 
    </information> 
    <item id="1" name="The Vice President Doesn't Say Anything about the Possibility of Him Being the Main Character" series="Baccano" season="1" episode="1"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
    <item id="4" name="blabla2" series="Baccano" season="1" episode="2"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
    <item id="3" name="abc" series="Baccano" season="2" episode="1"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
    <item id="5" name="first of c" series="c" season="1" episode="1"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
    <item id="2" name="blabla" series="c" season="1" episode="2"> 
     <synopsis>It's 1931 and...</synopsis> 
    </item> 
</collection> 
+0

漂亮乾淨的解決方案。 +1 – therealmarv

+1

最近我收到了這個答案的一個downvote。 Downvote沒有解釋是不好的,因爲我可能會錯過downvote的原因,我不能反駁或贊成。當你冷靜點時,請提供你的理由。我不在乎downvote,我關心糾正我的答案,我關心在這裏有好的答案。 –

+1

對這個問題的每個答案現在都有一個倒退。我也想知道原因。 –