2013-03-05 44 views
0

我有具有以下結構的XML文件(多個「實體」節點):XML節點模板 - 我應該使用XSLT嗎?

<!-- entities.xml --> 
<root> 
    <entity template="foo-template" kind="foo" name="bar"> 
     <groups> 
      <group id="1"> 
       <definition id="1" name="foobar" /> 
      </group> 
     </groups> 
    </entity> 
</root> 

許多entity節點具有相似的屬性和子節點。我希望允許用戶在單獨的文件中創建entity模板。引用該模板將進行如下:

<entity template="foo-template" kind="foo" ... /> 

從「富模板」每個屬性和子節點應該被複制到entity,除了那些已經存在(即允許覆蓋模板)。

我對XSLT不是很熟悉。它是完成這項任務的正確工具嗎,還是我最好沒有它來實施?

我正在使用C++和RapidXml,但可以使用其他XML庫。


編輯:例如

模板文件:

<!-- templates.xml --> 
<templates> 
    <entity template="foo-template" name="n/a" model="baz"> 
     <groups> 
      <group id="1"> 
       <definition id="1" name="def1" /> 
       <definition id="2" name="def2" /> 
      </group> 
      <group id="2"> 
       <definition id="1" name="def3" /> 
       <definition id="2" name="def4" /> 
      </group> 
     </groups> 
    </entity> 
</templates> 

輸出文件:

<!-- output.xml --> 
<root> 
    <entity kind="foo" name="bar" model="baz"> 
     <groups> 
      <group id="1"> 
       <definition id="1" name="foobar" /> 
      </group> 
      <group id="2"> 
       <definition id="1" name="def3" /> 
       <definition id="2" name="def4" /> 
      </group> 
     </groups> 
    </entity> 
</root> 

所以輸出包含第1組從 「entities.xml」 和組2從 「templates.xml」。無需將group節點合併爲相同的ID。

+0

我已經提供了一個答案,它將處理實體模板上的屬性,但重新閱讀我看到您也希望允許模板中的子元素的問題。在元素的情況下,「除了那些已經存在的」的標準是什麼?你可以編輯這個問題來包含一些關於什麼會被認爲是重複的,什麼不會(理想情況下,輸入,模板和相應的預期輸出的一些具體例子)的細節。 – 2013-03-05 14:20:15

+0

感謝您的詳細解答!我已經添加了一個例子,希望這有助於更好地理解我的問題。 – kshahar 2013-03-05 14:55:34

+0

好的,我編輯了我的答案來處理這個問題。 – 2013-03-05 15:18:31

回答

2

如果你有一個文件templates.xml看起來像

<templates> 
    <entity template="foo-template" kind="foo" name="bar" model="baz" /> 
    <!-- and other entity elements with different template="..." values --> 
</templates> 

那麼XSLT如下面將實現你以後

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

    <xsl:key name="kEntityTemplate" match="entity" use="@template" /> 

    <!-- identity template - copy everything not overridden by another template --> 
    <xsl:template match="@*|node"> 
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy> 
    </xsl:template> 

    <xsl:template match="entity[@template]"> 
    <xsl:variable name="thisEntity" select="." /> 
    <!-- switch to templates doc --> 
    <xsl:for-each select="document('templates.xml')"> 
     <xsl:variable name="template" 
     select="key('kEntityTemplate', $thisEntity/@template)" /> 

     <entity> 
     <!-- copy template attributes that are not overridden --> 
     <xsl:for-each select="$template/@*"> 
      <xsl:if test="not($thisEntity/@*[name() = name(current())])"> 
      <!-- if not, copy the one from the template --> 
      <xsl:apply-templates select="." /> 
      </xsl:if> 
     </xsl:for-each> 

     <!-- copy source attributes --> 
     <xsl:apply-templates select="$thisEntity/@*[name() != 'template']" /> 

     <!-- deal with elements --> 
     <xsl:if test="$thisEntity/groups/group | $template/groups/group"> 
      <groups> 
      <!-- here we select all group elements from the source plus 
       those group elements from the template that do not also exist 
       in the source, and sort the whole lot by id --> 
      <xsl:apply-templates select="$thisEntity/groups/group 
       | $template/groups/group[not(@id = $thisEntity/groups/group/@id)]"> 
       <xsl:sort select="@id" data-type="number" /> 
      </xsl:apply-templates> 
      </groups> 
     </xsl:if> 
     </entity> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

templates.xml文件需要在同一目錄作爲樣式表。

0

您在做任何類型的XML轉換之外有一個選擇是導入另一個XML文件,然後從標記中引用它。例如,請參閱here

這將要求您的用戶爲每種您可能不需要的模板類型分別提供模板文件。不過,由於kiss principle,我寧願進口。如果您不熟悉XSLT,那麼導入可能是更好的方法。

我希望這有助於!