我必須將大型xml檔案(>5Gb)匯入SOLR。我想先用SAXON EE10.6和流式xsl來轉換一個xml檔案。我已經讀到,使用SAXON EE10.6應該是可行的,但我得到了以下錯誤:
在第20行出現錯誤。
在mytest.xsl的第20行第34列出現錯誤。 XTSE3430 模板規則是不可流化的
- 有一個以上的消耗運算元。{<field {(attr{name=...}, ...)}/>}在第21行。 21,以及27行的{xsl:apply-templates} 。
- 模板規則的結果可以包含流式節點 模板規則不能流化
- 有一個以上的消耗運算元。{<field {(attr{name=...}, ...)}/>}在第21行,和{xsl:apply-templates}在第27行
- 模板規則的結果可以包含流式節點 。
我對流式xslt和Saxon不熟悉。如何讓我的xslt正確地用于流媒體,以輸出所需的Solr添加檔案xml。
我在這里用一個簡化版的xml和我使用的xslt做了一個擺弄。https://xsltfiddle.liberty-development.net/asoTKU
對于較小的xml檔案(<1Gb)來說,它的效果很好
uj5u.com熱心網友回復:
假設你的Properties元素和Category足夠 "小",可以被緩沖,我想
<xsl:styleheet version="3. 0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" expand-text="yes">
<xsl: output method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl: mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:mode name="grounded"/span>/>
<xsl:template match="屬性|類別">
<xsl: apply-templates select="copy-of()" mode="grounded"/>
</xsl:template>/span>
<xsl: template match="Category" mode="grounded">
<field name="Category">/span>{. }</field>。
<xsl:apply-templates mode="#current"/>/span>
</xsl:template>/span>
<xsl: 模板 match="Properties" mode="grounded">
<field name=" Properties">{. }</field>。
<xsl:apply-templates mode="#current"/>/span>
</xsl:template>/span>
<xsl: template match="Category/*" mode="grounded">
<field name="CAT_{local-name()}_s">/span>{。 }</field>。
</xsl:template>。
<xsl: 模板 match="Property" mode="grounded">
<field name="{key}_s"/span>> {value}</field>。
</xsl:template>/span>
<xsl:template match="Item/*[not(self::Category | self::Properties)]"/span>>
<field name="{local-name()}">/span>{. }</field>。
</xsl:template>。
<xsl:template match='/Items'/span>>
<add>
<xsl:apply-templates select="Item"/span>/>
</add>/span>
</xsl:template>
<xsl:template match="Item"/span>>
<xsl: variable name="pos" select="position()"/>
<doc>
<xsl:apply-templates>
<xsl:with-param name="pos">/span><xsl。 value-of select="$pos"/></xsl:with-param>/span>
</xsl:apply-templates>
</doc>
</xsl:template>
</xsl:styleheet>/span>
但是你的代碼(在<xsl:apply-templates select="Property"/>中做<xsl: template match="Property">)表明,也許Property元素可以遞回嵌套,如果代碼試影像上面那樣,使用copy-of()在記憶體中緩沖它遇到的第一個Property,那么任意嵌套都會導致記憶體問題。
然而,你的樣本XML并沒有任何嵌套的Property元素。
我所評論的xsl:fork策略的一部分被用于
<xsl:styleheet version="3. 0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" expand-text="yes">
<xsl: output method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:mode streamable="yes"/span>/>
<xsl: mode name="text" streamable="yes"/>
<xsl:mode name="grounded"/span>/>
<xsl:template match="Category"/span>>
<xsl: apply-templates select="copy-of()" mode="grounded"/>
</xsl:template>/span>
<xsl:template match="Properties">/span>
<xsl:fork>
<xsl:sequence>/span>
<field name="Properties">/span>
<xsl:apply-templates mode="text"/span>/>
</field>/span>
</xsl:sequence>
<xsl:sequence>/span>
<xsl:apply-templates/>
</xsl:sequence>/span>
</xsl:fork>/span>
</xsl:template>
<xsl: template match="Category" mode="grounded">
<field name="Category">/span>{. }</field>。
<xsl:apply-templates mode="#current"/>/span>
</xsl:template>/span>
<xsl: template match="Category/*" mode="grounded">
<field name="CAT_{local-name()}_s">/span>{。 }</field>。
</xsl:template>。
<xsl:template match="Property">/span>
<xsl: apply-templates select="copy-of()" mode="grounded"/>
</xsl:template>/span>
<xsl: 模板 match="Property" mode="grounded">
<field name="{key}_s"/span>> {value}</field>。
</xsl:template>/span>
<xsl:template match="Item/*[not(self::Category | self::Properties)]"/span>>
<field name="{local-name()}">/span>{. }</field>。
</xsl:template>。
<xsl:template match='/Items'/span>>
<add>
<xsl:apply-templates select="Item"/span>/>
</add>/span>
</xsl:template>
<xsl:template match="Item"/span>>
<xsl: variable name="pos" select="position()"/>
<doc>
<xsl:apply-templates>
<xsl:with-param name="pos">/span><xsl。 value-of select="$pos"/></xsl:with-param>/span>
</xsl:apply-templates>
</doc>
</xsl:template>
</xsl:styleheet>/span>
這避免了為每個Properties元素明確地構建 "一棵樹",但我不知道Saxon應用什么策略來確保xsl:fork的兩個分支都能訪問子代或子代的內容。
uj5u.com熱心網友回復:
XSLT 3.0流的規則是非常復雜的,而且很少有教程介紹,這對它沒有幫助。一個非常有用的資源是Abel Braaksma在XML Prague 2014上的演講:在https://www.xfront.com/Transcript-of-Abel-Braaksma-talk-on-XSLT-Streaming-at-XML-Prague-2014.pdf
最重要的規則是XSLT 3.0的流媒體。
需要記住的最重要的規則是:一個模板規則只能進行一次向下的選擇(它只有一次機會來掃描子代樹)。當你寫道:
這就是你所打破的規則。<xsl:template match="node()"> /span>
<xsl:element name="field">/span>
<xsl: attribute name="name">
<xsl:value-of select="local-name()"/span>/>
</xsl: attribute>
<xsl:value-of select="。"/>/span>
</xsl: element>
<xsl:apply-templates select="*"/span>/>
</xsl:template>/span>
實際上,該代碼可以簡化為
<xsl:template match="node()">
<field name="{local-name()}">/span>{. }</field>。
<xsl:apply-templates select="*"/span>/>
</xsl:template>/span>
但是這不會影響流的能力:你在處理匹配節點的后代兩次,一次是獲取字串值(.),一次是對子節點應用模板。
現在,在我看來,這個模板規則似乎只被用來處理 "葉子元素",也就是有一個文本節點的子元素,但沒有子元素。如果是這樣的話,那么<xsl:apply-templates select="*"/>就不會選擇任何東西:它是多余的,它可以被洗掉,這使得該規則可以流轉。
你得到的另一個錯誤資訊是,模板規則可以回傳流式節點。不允許回傳流式節點的原因有點微妙;它基本上使處理器無法進行資料流分析以證明流式是否可行。但又是<xsl:apply-templates select="*"/>造成了問題的原因,擺脫了它就解決了問題。
你的下一個問題是關于屬性元素的模板規則。你把它寫成了
<xsl:template match="Property">
<xsl:element name="field">/span>
<xsl: attribute name="name">
<xsl: value-of select="key"/>_s</xsl: attribute>
<xsl:value-of select="value"/span>/>
</xsl: element>
<xsl:apply-templates select="Property"/>/span>
</xsl:template>/span>
并且它簡化為:
<xsl:template match="Property"/span>>
<field name="{key}_s"/span>> {value}</field>。
<xsl:apply-templates select="Property"/>/span>
</xsl:template>/span>
這是在做三個向下的選擇。child::key, child::value, 和child::Property。在你的資料樣本中,沒有Property元素有一個叫做Property的子元素,所以也許<xsl:apply-templates/>/code>又是多余的。對于key和value,一個有用的技巧是將它們讀入一個map中:
<xsl:template match="Property">
<xsl: 變數 name="pair" as="map(*)">
<xsl:map>
<xsl: map-entry key="'key'" select="string(key)"/>
<xsl: map-entry key="'value'" select="string(value)"/>
</xsl:map>
</xsl:variable>
<field name="{$pair? key}_s">{$pair?value}< /field>
</xsl:template>/span>
這樣做的原因是,xsl:map(就像xsl:fork)是 "一次向下選擇 "規則的一個例外--地圖可以在一次輸入中建立起來。通過呼叫string(),我們小心翼翼地不把任何流式節點放入map中,所以我們后來需要的資料已經被捕獲在map中,我們永遠不需要再回到流式輸入檔案中去第二次讀取它。
我希望這能讓你感受到未來的方向。XSLT中的流并不適合膽小的人,但如果你有>5Gb的輸入檔案,那么你就沒有太多的選擇了。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/332442.html
標籤:
下一篇:從EXCEL匯入資料到SAS
