2016-01-04 27 views
2

說我有一個使用XIncludes,像這樣的源XML文檔:我可以在處理XInclude之前插入默認的xi:fallback實例嗎?

<?xml version="1.0" encoding="UTF-8"?> 
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01"> 
    <xi:include href="child01.xml"/> 
    <xi:include href="child02.xml"/> 
    <xi:include href="child03.xml"/> 
</parent> 

它XIncludes調用另外三個XML文檔看起來就像這樣:

child01.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<children> 
    <child xml:id="child01"> 
     <p>This is child 1.</p> 
    </child> 
</children> 

child02.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<children> 
    <child xml:id="child02"> 
     <p>This is child 2.</p> 
    </child> 
</children> 

child03.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<children> 
    <child xml:id="child03"> 
     <p>This is child 3.</p> 
    </child> 
</children> 

我有一個XSLT 2.0變換是這樣的:

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

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

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

    <xsl:template match="parent"> 
     <volume> 
     <xsl:apply-templates select="@*|.//child"/> 
     </volume> 
    </xsl:template> 

    <xsl:template match="child"> 
     <chapter> 
     <xsl:apply-templates select="@*|*|text()"/> 
     </chapter> 
    </xsl:template> 

    <xsl:template match="@*|*|text()"> 
     <xsl:copy copy-namespaces="no"> 
     <xsl:apply-templates select="@*|*|text()"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

當所有XIncludes引用的文件存在於同一文件夾中parent01.xml,我變換作品就好了,併產生這輸出:

<?xml version="1.0" encoding="UTF-8"?> 
<volume xml:id="parent01"> 
    <chapter xml:id="child01"> 
     <p>This is child 1.</p> 
    </chapter> 
    <chapter xml:id="child02"> 
     <p>This is child 2.</p> 
    </chapter> 
    <chapter xml:id="child03"> 
     <p>This is child 3.</p> 
    </chapter> 
</volume> 

但是,如果有一個文件 - 比如child02.xml - 丟失,則轉換將失敗。

將被阻止此故障已如果parent01.xml已列入十一:後備元素,像這樣:

<?xml version="1.0" encoding="UTF-8"?> 
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01"> 
    <xi:include href="child01.xml"> 
     <xi:fallback> 
     <child> 
      <p>The file is missing.</p> 
     </child> 
     </xi:fallback> 
    </xi:include> 
    <xi:include href="child02.xml"> 
     <xi:fallback> 
     <child> 
      <p>The file is missing.</p> 
     </child> 
     </xi:fallback> 
    </xi:include> 
    <xi:include href="child03.xml"> 
     <xi:fallback> 
     <child> 
      <p>The file is missing.</p> 
     </child> 
     </xi:fallback> 
    </xi:include> 
</parent> 

然後,輸出會一直如下:

<?xml version="1.0" encoding="UTF-8"?> 
<volume xml:id="parent01"> 
    <chapter xml:id="child01"> 
     <p>This is child 1.</p> 
    </chapter> 
    <chapter> 
     <p>The file is missing.</p> 
    </chapter> 
    <chapter xml:id="child03"> 
     <p>This is child 3.</p> 
    </chapter> 
</volume> 

我的問題是這樣的:是否可以編寫我的XSLT轉換來插入一個xi:fallback實例到每個xi:include 之前處理XInclude - 也就是添加一個默認的xi:fallback實例,其中不存在,然後pro如果xi:fallback實例已經存在,則將XInclude放置?

謝謝任何​​人可以提供的建議。

+0

和改造結果?但無論如何,我認爲答案將是:在XSLT轉換看到文檔之前,完成了新內容。 XInclude由XML解析器完成,該解析器位於XSLT處理的上游。 –

回答

1

將我的評論擴展爲完整的答案,因爲這是一個有趣的問題!

XSLT轉換不直接對XML文檔的文本內容進行操作,而是對內容的樹狀表示(DOM,XDM)進行操作。該輸入的表示或模型由XML解析器提供,理論上,它可以完全獨立於XSLT處理器。

現在重要的是:XML解析器負責執行XInclusions,而不是XSLT處理器。一旦XSLT處理器看到文檔模型,就無法知道XInclusion是否已經發生。不,據我所知,在單個XSLT轉換步驟中無法在XInclude之前和之後訪問文檔樹。您可以用不同的模式處理相同的輸入節點兩次,但是您還需要能夠從XSLT轉換中控制XML解析器的XInclude功能,這是不可能的。

我建議你花一點彎路分兩步解決您的問題:編寫應用沒有 XInclude的XSLT轉換(故意在你的XML IDE的XML解析器喜好像氧氣關閉這個功能或在命令行)來修復丟失的回退:

XSLT修復回退

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

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

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

    <xsl:template match="xi:include[not(xi:fallback)]"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*"/> 
      <xi:fallback> 
       <child> 
        <p>The file is missing.</p> 
       </child> 
      </xi:fallback> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

在此之後,臨時輸出文件看起來像:

<?xml version="1.0" encoding="UTF-8"?> 
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01"> 
    <xi:include href="child01.xml"> 
     <xi:fallback> 
      <child> 
       <p>The file is missing.</p> 
      </child> 
     </xi:fallback> 
    </xi:include> 
    <xi:include href="child02.xml"> 
     <xi:fallback> 
      <child> 
       <p>The file is missing.</p> 
      </child> 
     </xi:fallback> 
    </xi:include> 
    <xi:include href="child03.xml"> 
     <xi:fallback> 
      <child> 
       <p>The file is missing.</p> 
      </child> 
     </xi:fallback> 
    </xi:include> 
</parent> 

然後應用您已擁有的第二個轉換,但在再次啓用之前再次打開XInclude。這樣,在第二次轉換髮生之前,將丟失的文件替換爲其後備內容。


如果這是你不能接受,你可以看看XIPr,由Erik王爾德在XSLT 2.0純粹寫了XInclude處理器。通過將XIPr樣式表導入原始的XSLT樣式表,您可以首先提供缺失的回退,如上所示,然後process the result with mode="xipr"。在這種情況下,您應該禁用IDE或命令行工具的任何其他XInclude處理。

這裏是你如何能做到這一點(是的,它得到那種複雜):

首先,在href屬性指向您的文件必須是絕對的,因爲日XIPr處理器的特殊性:

XML輸入

<?xml version="1.0" encoding="UTF-8"?> 
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01"> 
    <xi:include href="file:/Users/User/Desktop/child01.xml"/> 
    <xi:include href="file:/Users/User/Desktop/child02.xml"/> 
    <xi:include href="file:/Users/User/Desktop/child03.xml"/> 
</parent> 

XSLT樣式表

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" 
    xmlns:xi="http://www.w3.org/2001/XInclude" 
    exclude-result-prefixes="xi"> 

    <xsl:import href="xipr.xsl"/> 

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

    <xsl:template match="/"> 
     <xsl:variable name="fixedfallbacks"> 
      <xsl:apply-templates select="." mode="fixfallbacks"/> 
     </xsl:variable> 
     <xsl:variable name="xincluded"> 
      <xsl:apply-templates select="$fixedfallbacks" mode="xipr"/> 
     </xsl:variable> 
     <xsl:apply-templates select="$xincluded/*" mode="#default"/> 
    </xsl:template> 

    <xsl:template match="xi:include[not(xi:fallback)]" mode="fixfallbacks"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()" mode="fixfallbacks"/> 
      <xi:fallback> 
       <child> 
        <p>The file is missing.</p> 
       </child> 
      </xi:fallback> 
     </xsl:copy> 
    </xsl:template> 

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

    <xsl:template match="parent"> 
     <volume> 
      <xsl:apply-templates select="@*|.//child"/> 
     </volume> 
    </xsl:template> 

    <xsl:template match="child"> 
     <chapter> 
      <xsl:apply-templates select="@*|*|text()"/> 
     </chapter> 
    </xsl:template> 

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

</xsl:stylesheet> 

執行此之前,你必須關閉你的XML解析器的XInclude的選項,下載XIPr樣式here,打開它,並更換線路52

<xsl:variable name="include-uri" select="resolve-uri(@href, document-uri(/))"/> 

<xsl:variable name="include-uri" select="resolve-uri(@href)"/> 

您必須這樣做,因爲您要求XIPr將X包含爲臨時樹的中間結果。如果在這樣的樹上使用document-uri(/),它將返回一個空序列,該序列不允許作爲resolve-uri()的第二個參數。

現在,終於,如果其中一個文件不存在,其結果將是

最終XML輸出

<?xml version="1.0" encoding="UTF-8"?> 
<volume xml:id="parent01"> 
    <chapter> 
     <p>The file is missing.</p> 
    </chapter> 
    <chapter xml:id="child02"> 
     <p>This is child 2.</p> 
    </chapter> 
    <chapter xml:id="child03"> 
     <p>This is child 3.</p> 
    </chapter> 
</volume> 
XSLT處理器和XML解析您使用到的XInclude什麼
+0

非常感謝,馬蒂亞斯 - 這是非常有用的信息。我會考慮這兩個選項;無論哪種方式,我都需要建立一個組織中的其他人可以輕鬆運行的流程:這可能是Oxygen轉型場景的仔細配置以及清晰的文檔。 – MDow

相關問題