2013-09-24 59 views
3

我的目標是分割包含各種內容(約2至15 GB)爲多個XML文件一個大的,單獨的XML文件,每片含某個實體類型,例如稍後可以通過SQL數據庫導入。我目前正在使用Saxon-EE版本9.5.1.2J,但其他任何XSL處理器都可以,如果它可以快速可靠地完成工作。使用單個XSL流存儲到一個大的XML文件分割成多個文件

以下是我已經想通了:

  • 撒克遜似乎是XSLT 3.0的事實上的標準處理器,而猛禽XML服務器似乎是另一個(更貴)的選擇。其他XSL處理器通常只支持XSLT 1.0。
  • 大文件可以使用XSLT 3.0流進行處理,以便整個文件不需要適應內存。注意:此功能僅在Saxon Enterprise Edition中可用。
  • 您可以使用<xsl:result-document>寫輸出到不同的文件,但你可以多次使用它在相同樣式表來寫同一個文件(顯然不是線程安全的)。
  • <xsl:for-each-group>與基團的由顯然是不可流傳送的
  • <xsl:stream>只能包含一個<xsl:iterate>塊,這是確定。但是:在該迭代塊內部,只能訪問當前節點和一個子節點的屬性(即使<xsl:for-each>在該節點上工作)。如果嘗試訪問第二個節點的值,則會出現「SXST0060:多個子表達式使用輸入流」錯誤。
  • <xsl:apply-templates><xsl:stream>(而不是迭代)需要模式streamer(如下圖所示)。但是,流只能像迭代一樣消耗一次 - 否則,您也會收到錯誤「SXST0060:多個子表達式消耗輸入流」。

我的結論是,目前可用的XSL處理器需要使用多個<xsl:stream>標籤寫入到不同的文件,這在實踐中意味着掃描輸入文件過大多次每個輸出文件。這是即使如此,編寫不同實體的相同輸出文件作爲解決辦法的時候,因爲這是不可能的「消費」同一個輸入流不止一次:

<xsl:mode name="s" streamable="yes"/> 

<xsl:template match="/"> 
    <xsl:stream href="input.xml"> 
     <xsl:apply-templates mode="s" select="content/articles"/> 
    </xsl:stream> 

    <xsl:stream href="input.xml"> 
     <xsl:apply-templates mode="s" select="content/articles/article/authors"/> 
    </xsl:stream> 
</xsl:template> 

它涉及到一個地步提取用解釋和更加複雜的命令行腳本從一個大的XML文件中的不同實體更快 - 從而使XSLT慢的和無用的比較:(

我希望有一個基於XSLT 3.0解決方案在那裏,工作原理預計多次掃描輸入文件?我沒有看到阻止這種用例的XSLT的基本技術限制。

回答

1

的問題實際上是相當容易解決:使用copy-of()使您能夠訪問節點和所有子節點(如在本例中波紋管name)一個迭代塊中:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" 
       omit-xml-declaration="no" 
       encoding="UTF-8" 
       indent="yes"/> 

    <xsl:template match="/"> 
     <xsl:stream href="input.xml"> 
      <resultset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
       <xsl:iterate select="content/articles/article"> 
        <xsl:for-each select="copy-of()/."> 
         <xsl:apply-templates select="."/> 
         <xsl:apply-templates select="authors/author"/> 
        </xsl:for-each> 
       </xsl:iterate> 
      </resultset> 
     </xsl:stream> 
    </xsl:template> 

    <xsl:template match="article"> 
     ... 
    </xsl:template> 

    <xsl:template match="author"> 
     ... 
    </xsl:template> 
</xsl:stylesheet> 

注:把複製的()直接在<xsl:iterate>不工作,你會得到一個OutOfMemoryError大型文件。模式流式傳輸不是必需的。

撒克遜可以在我的MacBook Air上每分鐘處理大約1 GB的XML。現在,我仍然將所有實體寫入同一個輸出文件,但MySQL可以過濾哪些節點導入每個表(http://dev.mysql.com/doc/refman/5.5/en/load-xml.html),因此解決方法不是主要問題。如果您發現如何將輸出寫入交替輸出文件,請告訴我。

我也得到了關於這個問題的反饋直接從邁克爾·凱(Saxonica):

是的,一旦你有不止一個向下的選擇,你需要 使用複印通手動整理的一些數據緩衝的()。我想 希望找到其他方法,限制可以在撒克遜放鬆爲 以及使事情更容易一些。

0

「使用簡單的命令行腳本更快」

我同意。您是可以從腳本調用的OS和商業命令行xml分離器。 它們使用快速向前讀取的XML解析器,它消耗的內存很少,可以一次完成分割。谷歌爲「分裂大的XML文件」

+0

XSLT將比我們的解釋腳本快得多,如果按預期工作更方便。恕我直言,它不是XSL流在xsl:iterate期間訪問多個單一(子)節點的根本限制。也許撒克遜可以在未來的版本中支持它,或者有一款已經支持它的處理器?能夠在一次運行中拆分和轉換大型XML文檔將是其他更低級別方法的主要優勢。 – lastzero

相關問題