2015-02-24 165 views
0

如果可能的話,我需要編寫轉換與此類似生成ID系統XSL

<media address="1234 A St."> 
    <book title="My Book" isbn="1324-1123-1456-1566" /> 
    <book title="Your Book" isbn="1232-1123-1456-1566" /> 
</media> 

的XML語法到這樣

<library> 

    <information> 
     <building id="1"> 
      <address>1234 A St.</address> 
     </building> 
    </information> 

    <medialist> 
     <book_definitions> 
      <book_definition id="2" /> 
      <book_definition id="3" /> 
     </book_definitions> 
     <book_metadata> 
      <metadata id="4"> 
       <isbn>1324-1123-1456-1566</isbn> 
       <book_definition_id>2</book_definition_id> 
      </metadata> 
      <metadata id="5"> 
       <isbn>1232-1123-1456-1566</isbn> 
       <book_definition_id>3</book_definition_id> 
      </metadata> 
     </book_metadata> 
     <book_instances> 
      <book_instance id="6"> 
       <book_definition_id>2</book_definition_id> 
       <book_metadata_id>4</book_metadata_id> 
       <title>My Book</title> 
      </book_instance> 
      <book_instance id="7"> 
       <book_definition_id>2</book_definition_id> 
       <book_metadata_id>5</book_metadata_id> 
       <title>Your Book</title> 
      </book_instance> 
     </book_instances> 
    </medialist> 
</library> 

我實現目標格式的格式的XSL文件有點複雜,但我無法控制它。

我已成功編寫XSL以使用模板模式正確轉換大部分XML標記。即。

<xsl:template match="/media/book" mode="definitions"> 
<xsl:template match="/media/book" mode="metadata"> 
<xsl:template match="/media/book" mode="instance"> 

不過,我一直在嘗試使用<的xsl:數>或其他一些技巧來生成ID的正確,但收效甚微。

目標格式對id有兩個約束:每個id屬性,無管理<元素>,名稱必須是唯一的。這些ID一旦被分類,必須是順序的,但它們可以以目標格式的任何順序出現,即(1,2,3,4,5)和(5,2,3,1,4)都可以接受,但( 1,2,4,5,6)不是。

有什麼辦法可以通過XSL來實現嗎?

+0

您確定您確實需要第二個約束嗎?將輸出節點鏈接到**不存在於輸入**中的其他輸出節點將會非常困難(並且應該正確地問你爲什麼還需要*)。 – 2015-02-24 20:14:14

+0

不幸的是,我確實需要第二個約束。但是,假設我沒有,是否有辦法只使用XSL來滿足第一個約束? – spectacularbob 2015-02-24 20:17:33

+0

還有一種方法可以滿足第二個約束條件。真正的問題是你願意付出多少努力。你和那些試圖幫助你的人。就我而言,我發現這項任務毫無興趣,因爲我看不出這對任何事情有什麼幫助。你的頭銜說的是主/外鍵;除了這些書已經有獨特和永久的ISBN這一事實之外,很明顯Books(你稱之爲book_definitions)是父表,所有其他表都應該鏈接到它,而不是一個級聯中的彼此。 – 2015-02-24 20:31:55

回答

1

雖然我只注意到伊恩·羅伯茨已經解釋過這種方法,我已經是要寫這一個XSLT,所以我將它張貼不管 - 下面的XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" /> 
    <xsl:strip-space elements="*" /> 
    <xsl:template match="/"> 
     <library> 
      <xsl:apply-templates /> 
     </library> 
    </xsl:template> 
    <xsl:template match="media"> 
     <xsl:variable name="current"> 
      <xsl:number /> 
     </xsl:variable> 
     <information> 
      <building> 
       <xsl:attribute name="id"> 
        <xsl:value-of select="$current" /> 
       </xsl:attribute> 
       <address> 
        <xsl:value-of select="@address" /> 
       </address> 
      </building> 
     </information> 
     <medialist> 
      <book_definitions> 
       <xsl:apply-templates mode="definition"> 
        <xsl:with-param name="current"> 
         <xsl:value-of select="$current" /> 
        </xsl:with-param> 
       </xsl:apply-templates> 
      </book_definitions> 
      <book_metadata> 
       <xsl:apply-templates mode="metadata"> 
        <xsl:with-param name="current"> 
         <xsl:value-of select="$current" /> 
        </xsl:with-param> 
       </xsl:apply-templates> 
      </book_metadata> 
      <book_instances> 
       <xsl:apply-templates mode="instances"> 
        <xsl:with-param name="current"> 
         <xsl:value-of select="$current" /> 
        </xsl:with-param> 
       </xsl:apply-templates> 
      </book_instances> 
     </medialist> 
    </xsl:template> 
    <xsl:template match="book" mode="definition"> 
     <xsl:param name="current" /> 
     <book_definition id="{(position() + $current)}" /> 
    </xsl:template> 
    <xsl:template match="book" mode="metadata"> 
     <xsl:param name="current" /> 
     <metadata id="{(position() + $current + count(parent::media/book))}"> 
      <isbn> 
       <xsl:value-of select="@isbn" /> 
      </isbn> 
      <book_definition_id> 
       <xsl:value-of select="position() + $current" /> 
      </book_definition_id> 
     </metadata> 
    </xsl:template> 
    <xsl:template match="book" mode="instances"> 
     <xsl:param name="current" /> 
     <book_instance id="{(position() + 2*count(parent::media/book) + $current)}"> 
      <book_definition_id> 
       <xsl:value-of select="position() + $current" /> 
      </book_definition_id> 
      <book_metadata_id> 
       <xsl:value-of select="position() + $current + count(parent::media/book)" /> 
      </book_metadata_id> 
      <title> 
       <xsl:value-of select="@title" /> 
      </title> 
     </book_instance> 
    </xsl:template> 
</xsl:transform> 

當應用到你的輸入XML生成輸出

<library> 
<information> 
    <building id="1"> 
    <address>1234 A St.</address> 
    </building> 
</information> 
<medialist> 
    <book_definitions> 
     <book_definition id="2"/> 
     <book_definition id="3"/> 
    </book_definitions> 
    <book_metadata> 
     <metadata id="4"> 
     <isbn>1324-1123-1456-1566</isbn> 
     <book_definition_id>2</book_definition_id> 
     </metadata> 
     <metadata id="5"> 
     <isbn>1232-1123-1456-1566</isbn> 
     <book_definition_id>3</book_definition_id> 
     </metadata> 
    </book_metadata> 
    <book_instances> 
     <book_instance id="6"> 
     <book_definition_id>2</book_definition_id> 
     <book_metadata_id>4</book_metadata_id> 
     <title>My Book</title> 
     </book_instance> 
     <book_instance id="7"> 
     <book_definition_id>3</book_definition_id> 
     <book_metadata_id>5</book_metadata_id> 
     <title>Your Book</title> 
     </book_instance> 
    </book_instances> 
    </medialist> 
</library> 

由於不清楚輸入XML是否包含多個media元素 - 例如然後應該以id 8開始的下一個建築物 - 我使用數字作爲參數而不是僅添加1.
請注意,此模板不適用於第二個media元素 - 這將僅以2開始,作爲id的值 - 如果實際輸入XML包含多個建築物/ media元素,則必須相應地進行調整。
對於書中的定義,id是當前圖書的位置之和參數current的價值:

<book_definition id="{(position() + $current)}" /> 

元數據id是當前圖書的位置的總和,所有書籍當前/父media元素和current

<metadata id="{(position() + $current + count(parent::media/book))}"> 

和書實例ID,考慮到元數據之前生成的ID,是當前的書,current的位置的父的所有書籍的總和media元素* 2:

<book_instance id="{(position() + 2*count(parent::media/book) + $current)}"> 
1

在我看來,既然(除了建築物),你總是爲每個不同的「種類」的節點生成一本書ID,你可以通過根據公式生成它們來保證獨特和順序的ID。如果你有N個書,那麼你可以「法令」是

  • 建設始終是ID 1
  • book_definition的書m是始終1+m(因此運行從2個至N + 1)
  • 的對於本書米的元數據是(N+1)+m
  • 實例爲(2N+1)+m

如果按照這個方案,隨處都可以簡單地計算出合適的交叉引用book_definition_id等,不需要查找表。