使兄弟节点在可流式模式下有一个父节点
Make sibling nodes have a parent in a streamable mode
有一个包含很多同级 <Line>
节点的文档,如下所示
<Report>
<Date>2020-07-25</Date>
<Number>12</Number>
<Line>
<LineNumber>1</LineNumber>
<Description>Some text</Description>
<Quantity>5</Quantity>
</Line>
<Line>
<LineNumber>2</LineNumber>
<Description>Some other text</Description>
<Quantity>9</Quantity>
</Line>
</Report>
我想得到一个输出,这样的节点被组合成一个父节点,如
<INV>
<HEAD>
<DTM>2020-07-25</DTM>
<ID>12</ID>
</HEAD>
<LINES>
<LINE>
<NUM>1</NUM>
<DESC>Some text</DESC>
<QTY>5</QTY>
</LINE>
<LINE>
<NUM>2</NUM>
<DESC>Some other text</DESC>
<QTY>9</QTY>
</LINE>
</LINES>
</INV>
该问题的一个可能解决方案是按名称对元素进行分组
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="yes" on-no-match="deep-skip"/>
<xsl:mode name="non-streamable" on-no-match="shallow-skip"/>
<xsl:template match="/Report">
<xsl:element name="INV">
<xsl:fork>
<xsl:for-each-group select="*" group-by="name() = 'Line'">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:element name="LINES">
<xsl:apply-templates select="current-group()/copy-of()" mode="non-streamable"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="HEAD">
<xsl:apply-templates select="current-group()/copy-of()" mode="non-streamable"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:fork>
</xsl:element>
</xsl:template>
<xsl:template match="Date" mode="non-streamable">
<DTM>
<xsl:value-of select="."/>
</DTM>
</xsl:template>
<xsl:template match="Number" mode="non-streamable">
<ID>
<xsl:value-of select="."/>
</ID>
</xsl:template>
<xsl:template match="Line" mode="non-streamable">
<LINE>
<NUM>
<xsl:value-of select="LineNumber"/>
</NUM>
<DESC>
<xsl:value-of select="Description"/>
</DESC>
<QTY>
<xsl:value-of select="Quantity"/>
</QTY>
</LINE>
</xsl:template>
</xsl:stylesheet>
但是使用这种方法我面临着高内存消耗,它需要大约 2.5 GB 的 RAM 来转换一个现实生活中的 500 Mb 文档,其中包含大约 100 万行。这些分组的元素是否存储在内存中?我们能避免吗?
还有其他方法可以执行此任务吗?
xsl:for-each-group
和 @group-by
指令就技术定义而言是可流式的,因为它可以在内存中没有完整源文档的情况下运行;然而,它在内存中构建选定的组,因此它仍然有很高的内存需求。所以这不是正确的方法。
我认为您在这里的路线是正确的,但是您可以使用 group-adjacent 而不是 group-by,这使得它完全可以流式传输。这是我的解决方案:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="yes" on-no-match="deep-skip"/>
<xsl:mode name="non-streamable" on-no-match="shallow-skip"/>
<xsl:template match="/Report">
<xsl:element name="INV">
<xsl:for-each-group select="*" group-adjacent="name() = 'Line'">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:element name="LINES">
<xsl:apply-templates select="current-group()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="HEAD">
<xsl:apply-templates select="current-group()/copy-of()" mode="non-streamable"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:element>
</xsl:template>
<xsl:template match="Date" mode="non-streamable">
<DTM>
<xsl:value-of select="."/>
</DTM>
</xsl:template>
<xsl:template match="Number" mode="non-streamable">
<ID>
<xsl:value-of select="."/>
</ID>
</xsl:template>
<xsl:template match="Line">
<LINE>
<xsl:apply-templates/>
</LINE>
</xsl:template>
<xsl:template match="LineNumber">
<NUM>
<xsl:value-of select="."/>
</NUM>
</xsl:template>
<xsl:template match="Description">
<DESC>
<xsl:value-of select="."/>
</DESC>
</xsl:template>
<xsl:template match="Quantity">
<QTY>
<xsl:value-of select="."/>
</QTY>
</xsl:template>
</xsl:stylesheet>
我没有在大输入文件上尝试过,但我认为它应该在常量内存中运行。
有一个包含很多同级 <Line>
节点的文档,如下所示
<Report>
<Date>2020-07-25</Date>
<Number>12</Number>
<Line>
<LineNumber>1</LineNumber>
<Description>Some text</Description>
<Quantity>5</Quantity>
</Line>
<Line>
<LineNumber>2</LineNumber>
<Description>Some other text</Description>
<Quantity>9</Quantity>
</Line>
</Report>
我想得到一个输出,这样的节点被组合成一个父节点,如
<INV>
<HEAD>
<DTM>2020-07-25</DTM>
<ID>12</ID>
</HEAD>
<LINES>
<LINE>
<NUM>1</NUM>
<DESC>Some text</DESC>
<QTY>5</QTY>
</LINE>
<LINE>
<NUM>2</NUM>
<DESC>Some other text</DESC>
<QTY>9</QTY>
</LINE>
</LINES>
</INV>
该问题的一个可能解决方案是按名称对元素进行分组
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="yes" on-no-match="deep-skip"/>
<xsl:mode name="non-streamable" on-no-match="shallow-skip"/>
<xsl:template match="/Report">
<xsl:element name="INV">
<xsl:fork>
<xsl:for-each-group select="*" group-by="name() = 'Line'">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:element name="LINES">
<xsl:apply-templates select="current-group()/copy-of()" mode="non-streamable"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="HEAD">
<xsl:apply-templates select="current-group()/copy-of()" mode="non-streamable"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:fork>
</xsl:element>
</xsl:template>
<xsl:template match="Date" mode="non-streamable">
<DTM>
<xsl:value-of select="."/>
</DTM>
</xsl:template>
<xsl:template match="Number" mode="non-streamable">
<ID>
<xsl:value-of select="."/>
</ID>
</xsl:template>
<xsl:template match="Line" mode="non-streamable">
<LINE>
<NUM>
<xsl:value-of select="LineNumber"/>
</NUM>
<DESC>
<xsl:value-of select="Description"/>
</DESC>
<QTY>
<xsl:value-of select="Quantity"/>
</QTY>
</LINE>
</xsl:template>
</xsl:stylesheet>
但是使用这种方法我面临着高内存消耗,它需要大约 2.5 GB 的 RAM 来转换一个现实生活中的 500 Mb 文档,其中包含大约 100 万行。这些分组的元素是否存储在内存中?我们能避免吗?
还有其他方法可以执行此任务吗?
xsl:for-each-group
和 @group-by
指令就技术定义而言是可流式的,因为它可以在内存中没有完整源文档的情况下运行;然而,它在内存中构建选定的组,因此它仍然有很高的内存需求。所以这不是正确的方法。
我认为您在这里的路线是正确的,但是您可以使用 group-adjacent 而不是 group-by,这使得它完全可以流式传输。这是我的解决方案:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="yes" on-no-match="deep-skip"/>
<xsl:mode name="non-streamable" on-no-match="shallow-skip"/>
<xsl:template match="/Report">
<xsl:element name="INV">
<xsl:for-each-group select="*" group-adjacent="name() = 'Line'">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:element name="LINES">
<xsl:apply-templates select="current-group()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="HEAD">
<xsl:apply-templates select="current-group()/copy-of()" mode="non-streamable"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:element>
</xsl:template>
<xsl:template match="Date" mode="non-streamable">
<DTM>
<xsl:value-of select="."/>
</DTM>
</xsl:template>
<xsl:template match="Number" mode="non-streamable">
<ID>
<xsl:value-of select="."/>
</ID>
</xsl:template>
<xsl:template match="Line">
<LINE>
<xsl:apply-templates/>
</LINE>
</xsl:template>
<xsl:template match="LineNumber">
<NUM>
<xsl:value-of select="."/>
</NUM>
</xsl:template>
<xsl:template match="Description">
<DESC>
<xsl:value-of select="."/>
</DESC>
</xsl:template>
<xsl:template match="Quantity">
<QTY>
<xsl:value-of select="."/>
</QTY>
</xsl:template>
</xsl:stylesheet>
我没有在大输入文件上尝试过,但我认为它应该在常量内存中运行。