我正在使用地图进行流式传输和分组,需要有关如何提高性能的建议
I'm using maps for streaming and grouping, need advice on how to improve the performance
我的源数据是这样的,它真的很大 xml 2+ GB。
<?xml version="1.0" encoding="UTF-8"?>
<Journal_Lines>
<jrnl1 CY="USD" CCD="1001" CC="11062" IsPyJrl="1" AID="11382" LAI="107709"
TLCCr="11062" TCAmt="222.85" TDAmt="0" CDI="C" CDAmt="222.85" DN=""
EDt="2019-06-16-07:00" SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="11062" IsPyJrl="1" AID="11382" LAI="240997"
TLCCr="11062" TCAmt="0" TDAmt="222.85" CDI="D" CDAmt="222.85" DN=""
EDt="2019-06-16-07:00" SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="16835" IsPyJrl="1" AID="12661" LAI="107769"
TLCCr="16835" TCAmt="94.06" TDAmt="0" CDI="C" CDAmt="94.06" DN="" EDt="2019-06-16-07:00"
SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="16835" IsPyJrl="1" AID="12661" LAI="240997"
TLCCr="16835" TCAmt="0" TDAmt="94.06" CDI="D" CDAmt="94.06" DN="" EDt="2019-06-16-07:00"
SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="19655" IsPyJrl="1" AID="12731" LAI="240997"
TLCCr="19655" TCAmt="0" TDAmt="899.11" CDI="D" CDAmt="899.11" DN=""
EDt="2019-06-16-07:00" SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="19655" IsPyJrl="1" AID="12731" LAI="107709"
TLCCr="19655" TCAmt="899.11" TDAmt="0" CDI="C" CDAmt="899.11" DN=""
EDt="2019-06-16-07:00" SCd="" HURCl="0"/>
</Journal_Lines>
我的输出是
<Journal_Lines xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<Group CCD="1001" CC="11062">
<Jrnln CY="USD" CCD="1001" CC="11062" IsPyJrl="1" AID="11382" LAI="107709" TLCCr="11062"
TCAmt="222.85" TDAmt="0" CDI="C" CDAmt="222.85" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
<Jrnln CY="USD" CCD="1001" CC="11062" IsPyJrl="1" AID="11382" LAI="240997" TLCCr="11062"
TCAmt="0" TDAmt="222.85" CDI="D" CDAmt="222.85" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
</Group>
<Group CCD="1001" CC="16835">
<Jrnln CY="USD" CCD="1001" CC="16835" IsPyJrl="1" AID="12661" LAI="107769" TLCCr="16835"
TCAmt="94.06" TDAmt="0" CDI="C" CDAmt="94.06" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
<Jrnln CY="USD" CCD="1001" CC="16835" IsPyJrl="1" AID="12661" LAI="240997" TLCCr="16835"
TCAmt="0" TDAmt="94.06" CDI="D" CDAmt="94.06" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
</Group>
<Group CCD="1001" CC="19655">
<Jrnln CY="USD" CCD="1001" CC="19655" IsPyJrl="1" AID="12731" LAI="240997" TLCCr="19655"
TCAmt="0" TDAmt="899.11" CDI="D" CDAmt="899.11" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
<Jrnln CY="USD" CCD="1001" CC="19655" IsPyJrl="1" AID="12731" LAI="107709" TLCCr="19655"
TCAmt="899.11" TDAmt="0" CDI="C" CDAmt="899.11" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
</Group>
</Journal_Lines>
我正在按 CC 和 CCD 进行分组和排序,我当前的代码在下面并且可以正常工作。但是需要很长时间。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:output indent="no"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:variable name="vElementMap" as="map(*)"
select="map {
1:'CY', 2:'CCD', 3:'CC', 4:'IsPyJrl', 5:'AID',
6:'LAI', 7:'TLCCr', 8:'TCAmt', 9:'TDAmt', 10:'CDI',
11:'CDAmt', 12:'DN', 13:'EDt', 14:'SCd', 15:'HURCl' }"
/>
<xsl:template match="/">
<xsl:iterate select="Journal_Lines/jrnl1">
<xsl:param name="mapJournalLines" as="map(xs:string, xs:string)" select="map{}"/>
<xsl:on-completion>
<Journal_Lines>
<!-- Sort data -->
<xsl:for-each select="map:for-each($mapJournalLines, function ($k, $v) {$k})">
<xsl:sort select="."/>
<Group CCD="{substring-before(.,'^')}" CC="{substring-after(.,'^')}">
<xsl:for-each select="tokenize($mapJournalLines(.),'\^')">
<Jrnln>
<xsl:for-each select="tokenize(.,'\|')">
<xsl:attribute name="{$vElementMap(position())}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
</Jrnln>
</xsl:for-each>
</Group>
</xsl:for-each>
</Journal_Lines>
</xsl:on-completion>
<xsl:variable name="current-entry" select="copy-of()"/>
<xsl:variable name="vKey" select="$current-entry/@CCD || '^' || $current-entry/@CC"/>
<xsl:variable name="vValue">
<xsl:for-each select="$current-entry/@*">
<xsl:if test="position() ne 1">|</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="mapJournalLines"
select="
if (map:contains($mapJournalLines, xs:string($vKey))) then
map:put($mapJournalLines, xs:string($vKey), $mapJournalLines(xs:string($vKey)) || '^' || xs:string($vValue))
else
map:put($mapJournalLines, xs:string($vKey), xs:string($vValue))"
/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
我正在将单个 jrnl1 节点转换为单个竖线分隔线,多个分组线由 ^ 分隔
这适用于小负载,但需要永远处理大数据。
感谢任何帮助。
您以属性为中心的数据似乎是流式传输的良好输入 xsl:fork/xsl:for-each-group
:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all">
<xsl:output indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:template match="Journal_Lines">
<xsl:copy>
<xsl:fork>
<xsl:for-each-group select="jrnl1" composite="yes" group-by="@CCD, @CC">
<Group CCD="{current-grouping-key()[1]}" CC="{current-grouping-key()[2]}">
<xsl:apply-templates select="current-group()"/>
</Group>
</xsl:for-each-group>
</xsl:fork>
</xsl:copy>
</xsl:template>
<xsl:template match="jrnl1">
<Jrnln>
<xsl:copy-of select="@*"/>
</Jrnln>
</xsl:template>
</xsl:stylesheet>
然而,即使是这种方法也需要 XSLT 处理器在内存中缓冲组,因为直到最后一个元素被处理它属于哪个组时才可以确定,或者换句话说,它不能推出和关闭任何在处理最后一个元素之前进行分组。只有 group-adjacent
会减少缓冲的需要(以及 xsl:fork
的使用),但这显然需要输入将元素分组在一起,这些元素已经相互跟随。
使用排序与 XSLT 3 中的流式处理并不真正兼容,我认为对它的任何使用都会破坏任何流式分析,您需要加入 copy-of()
,我不确定它是否有任何优势优于传统 XSLT:
<xsl:template match="Journal_Lines">
<xsl:copy>
<xsl:for-each-group select="jrnl1!copy-of()" composite="yes" group-by="@CCD, @CC">
<xsl:sort select="current-grouping-key()[1]"/>
<xsl:sort select="current-grouping-key()[2]"/>
<Group CCD="{current-grouping-key()[1]}" CC="{current-grouping-key()[2]}">
<xsl:apply-templates select="current-group()"/>
</Group>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
可能值得研究专用的 XML 数据库系统,例如 eXist 或 BaseX,如果它们(主要基于 XQuery)的处理允许比独立的 XSLT 3 处理器具有更高的性能和更少的内存密集型排序和分组。
对于您当前使用字符串映射的方法,您连接并标记化可能值得检查使用嵌套数组或 array/sequence 的嵌套是否性能更好,或者可能只是存储您已经拥有的元素 copy-of()
ed 也比连接和拆分字符串更快:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:output indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:variable name="vElementMap" as="map(*)"
select="map {
1:'CY', 2:'CCD', 3:'CC', 4:'IsPyJrl', 5:'AID',
6:'LAI', 7:'TLCCr', 8:'TCAmt', 9:'TDAmt', 10:'CDI',
11:'CDAmt', 12:'DN', 13:'EDt', 14:'SCd', 15:'HURCl' }"
/>
<xsl:template match="/">
<xsl:iterate select="Journal_Lines/jrnl1">
<xsl:param name="mapJournalLines" as="map(xs:string, element(jrnl1)*)" select="map{}"/>
<xsl:on-completion>
<Journal_Lines>
<!-- Sort data -->
<xsl:for-each select="map:keys($mapJournalLines)">
<xsl:sort select="."/>
<Group CCD="{substring-before(.,'^')}" CC="{substring-after(.,'^')}">
<xsl:for-each select="$mapJournalLines(.)">
<Jrnln>
<xsl:copy-of select="@*"/>
</Jrnln>
</xsl:for-each>
</Group>
</xsl:for-each>
</Journal_Lines>
</xsl:on-completion>
<xsl:variable name="current-entry" select="copy-of()"/>
<xsl:variable name="vKey" as="xs:string" select="$current-entry/@CCD || '^' || $current-entry/@CC"/>
<xsl:next-iteration>
<xsl:with-param name="mapJournalLines"
select="
if (map:contains($mapJournalLines, $vKey)) then
map:put($mapJournalLines, $vKey, ($mapJournalLines($vKey), $current-entry))
else
map:put($mapJournalLines, $vKey, $current-entry)"
/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
最后,为了保持字符串数据映射的原始方法,但为了避免所有的连接和标记化,您可以尝试 map(xs:string, array(xs:string)*)
,即将每组数据存储为序列的映射字符串数组,其中每个数组代表最终输出中的一行:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:output indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:variable name="vElementMap" as="map(*)"
select="map {
1:'CY', 2:'CCD', 3:'CC', 4:'IsPyJrl', 5:'AID',
6:'LAI', 7:'TLCCr', 8:'TCAmt', 9:'TDAmt', 10:'CDI',
11:'CDAmt', 12:'DN', 13:'EDt', 14:'SCd', 15:'HURCl' }"
/>
<xsl:template match="/">
<xsl:iterate select="Journal_Lines/jrnl1">
<xsl:param name="mapJournalLines" as="map(xs:string, array(xs:string)*)" select="map{}"/>
<xsl:on-completion>
<Journal_Lines>
<!-- Sort data -->
<xsl:for-each select="map:keys($mapJournalLines)">
<xsl:sort select="."/>
<Group CCD="{substring-before(.,'^')}" CC="{substring-after(.,'^')}">
<xsl:for-each select="$mapJournalLines(.)">
<Jrnln>
<xsl:for-each select="?*">
<xsl:attribute name="{$vElementMap(position())}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
</Jrnln>
</xsl:for-each>
</Group>
</xsl:for-each>
</Journal_Lines>
</xsl:on-completion>
<xsl:variable name="vKey" as="xs:string" select="@CCD || '^' || @CC"/>
<xsl:variable name="vValue" as="array(xs:string)*" select="array { @*!string() }"/>
<xsl:next-iteration>
<xsl:with-param name="mapJournalLines"
select="
if (map:contains($mapJournalLines, $vKey)) then
map:put($mapJournalLines, $vKey, ($mapJournalLines($vKey), $vValue))
else
map:put($mapJournalLines, $vKey, $vValue)"
/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
我的源数据是这样的,它真的很大 xml 2+ GB。
<?xml version="1.0" encoding="UTF-8"?>
<Journal_Lines>
<jrnl1 CY="USD" CCD="1001" CC="11062" IsPyJrl="1" AID="11382" LAI="107709"
TLCCr="11062" TCAmt="222.85" TDAmt="0" CDI="C" CDAmt="222.85" DN=""
EDt="2019-06-16-07:00" SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="11062" IsPyJrl="1" AID="11382" LAI="240997"
TLCCr="11062" TCAmt="0" TDAmt="222.85" CDI="D" CDAmt="222.85" DN=""
EDt="2019-06-16-07:00" SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="16835" IsPyJrl="1" AID="12661" LAI="107769"
TLCCr="16835" TCAmt="94.06" TDAmt="0" CDI="C" CDAmt="94.06" DN="" EDt="2019-06-16-07:00"
SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="16835" IsPyJrl="1" AID="12661" LAI="240997"
TLCCr="16835" TCAmt="0" TDAmt="94.06" CDI="D" CDAmt="94.06" DN="" EDt="2019-06-16-07:00"
SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="19655" IsPyJrl="1" AID="12731" LAI="240997"
TLCCr="19655" TCAmt="0" TDAmt="899.11" CDI="D" CDAmt="899.11" DN=""
EDt="2019-06-16-07:00" SCd="" HURCl="0"/>
<jrnl1 CY="USD" CCD="1001" CC="19655" IsPyJrl="1" AID="12731" LAI="107709"
TLCCr="19655" TCAmt="899.11" TDAmt="0" CDI="C" CDAmt="899.11" DN=""
EDt="2019-06-16-07:00" SCd="" HURCl="0"/>
</Journal_Lines>
我的输出是
<Journal_Lines xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<Group CCD="1001" CC="11062">
<Jrnln CY="USD" CCD="1001" CC="11062" IsPyJrl="1" AID="11382" LAI="107709" TLCCr="11062"
TCAmt="222.85" TDAmt="0" CDI="C" CDAmt="222.85" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
<Jrnln CY="USD" CCD="1001" CC="11062" IsPyJrl="1" AID="11382" LAI="240997" TLCCr="11062"
TCAmt="0" TDAmt="222.85" CDI="D" CDAmt="222.85" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
</Group>
<Group CCD="1001" CC="16835">
<Jrnln CY="USD" CCD="1001" CC="16835" IsPyJrl="1" AID="12661" LAI="107769" TLCCr="16835"
TCAmt="94.06" TDAmt="0" CDI="C" CDAmt="94.06" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
<Jrnln CY="USD" CCD="1001" CC="16835" IsPyJrl="1" AID="12661" LAI="240997" TLCCr="16835"
TCAmt="0" TDAmt="94.06" CDI="D" CDAmt="94.06" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
</Group>
<Group CCD="1001" CC="19655">
<Jrnln CY="USD" CCD="1001" CC="19655" IsPyJrl="1" AID="12731" LAI="240997" TLCCr="19655"
TCAmt="0" TDAmt="899.11" CDI="D" CDAmt="899.11" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
<Jrnln CY="USD" CCD="1001" CC="19655" IsPyJrl="1" AID="12731" LAI="107709" TLCCr="19655"
TCAmt="899.11" TDAmt="0" CDI="C" CDAmt="899.11" DN="" EDt="2019-06-16-07:00" SCd=""
HURCl="0"/>
</Group>
</Journal_Lines>
我正在按 CC 和 CCD 进行分组和排序,我当前的代码在下面并且可以正常工作。但是需要很长时间。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:output indent="no"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:variable name="vElementMap" as="map(*)"
select="map {
1:'CY', 2:'CCD', 3:'CC', 4:'IsPyJrl', 5:'AID',
6:'LAI', 7:'TLCCr', 8:'TCAmt', 9:'TDAmt', 10:'CDI',
11:'CDAmt', 12:'DN', 13:'EDt', 14:'SCd', 15:'HURCl' }"
/>
<xsl:template match="/">
<xsl:iterate select="Journal_Lines/jrnl1">
<xsl:param name="mapJournalLines" as="map(xs:string, xs:string)" select="map{}"/>
<xsl:on-completion>
<Journal_Lines>
<!-- Sort data -->
<xsl:for-each select="map:for-each($mapJournalLines, function ($k, $v) {$k})">
<xsl:sort select="."/>
<Group CCD="{substring-before(.,'^')}" CC="{substring-after(.,'^')}">
<xsl:for-each select="tokenize($mapJournalLines(.),'\^')">
<Jrnln>
<xsl:for-each select="tokenize(.,'\|')">
<xsl:attribute name="{$vElementMap(position())}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
</Jrnln>
</xsl:for-each>
</Group>
</xsl:for-each>
</Journal_Lines>
</xsl:on-completion>
<xsl:variable name="current-entry" select="copy-of()"/>
<xsl:variable name="vKey" select="$current-entry/@CCD || '^' || $current-entry/@CC"/>
<xsl:variable name="vValue">
<xsl:for-each select="$current-entry/@*">
<xsl:if test="position() ne 1">|</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="mapJournalLines"
select="
if (map:contains($mapJournalLines, xs:string($vKey))) then
map:put($mapJournalLines, xs:string($vKey), $mapJournalLines(xs:string($vKey)) || '^' || xs:string($vValue))
else
map:put($mapJournalLines, xs:string($vKey), xs:string($vValue))"
/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
我正在将单个 jrnl1 节点转换为单个竖线分隔线,多个分组线由 ^ 分隔 这适用于小负载,但需要永远处理大数据。
感谢任何帮助。
您以属性为中心的数据似乎是流式传输的良好输入 xsl:fork/xsl:for-each-group
:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all">
<xsl:output indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:template match="Journal_Lines">
<xsl:copy>
<xsl:fork>
<xsl:for-each-group select="jrnl1" composite="yes" group-by="@CCD, @CC">
<Group CCD="{current-grouping-key()[1]}" CC="{current-grouping-key()[2]}">
<xsl:apply-templates select="current-group()"/>
</Group>
</xsl:for-each-group>
</xsl:fork>
</xsl:copy>
</xsl:template>
<xsl:template match="jrnl1">
<Jrnln>
<xsl:copy-of select="@*"/>
</Jrnln>
</xsl:template>
</xsl:stylesheet>
然而,即使是这种方法也需要 XSLT 处理器在内存中缓冲组,因为直到最后一个元素被处理它属于哪个组时才可以确定,或者换句话说,它不能推出和关闭任何在处理最后一个元素之前进行分组。只有 group-adjacent
会减少缓冲的需要(以及 xsl:fork
的使用),但这显然需要输入将元素分组在一起,这些元素已经相互跟随。
使用排序与 XSLT 3 中的流式处理并不真正兼容,我认为对它的任何使用都会破坏任何流式分析,您需要加入 copy-of()
,我不确定它是否有任何优势优于传统 XSLT:
<xsl:template match="Journal_Lines">
<xsl:copy>
<xsl:for-each-group select="jrnl1!copy-of()" composite="yes" group-by="@CCD, @CC">
<xsl:sort select="current-grouping-key()[1]"/>
<xsl:sort select="current-grouping-key()[2]"/>
<Group CCD="{current-grouping-key()[1]}" CC="{current-grouping-key()[2]}">
<xsl:apply-templates select="current-group()"/>
</Group>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
可能值得研究专用的 XML 数据库系统,例如 eXist 或 BaseX,如果它们(主要基于 XQuery)的处理允许比独立的 XSLT 3 处理器具有更高的性能和更少的内存密集型排序和分组。
对于您当前使用字符串映射的方法,您连接并标记化可能值得检查使用嵌套数组或 array/sequence 的嵌套是否性能更好,或者可能只是存储您已经拥有的元素 copy-of()
ed 也比连接和拆分字符串更快:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:output indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:variable name="vElementMap" as="map(*)"
select="map {
1:'CY', 2:'CCD', 3:'CC', 4:'IsPyJrl', 5:'AID',
6:'LAI', 7:'TLCCr', 8:'TCAmt', 9:'TDAmt', 10:'CDI',
11:'CDAmt', 12:'DN', 13:'EDt', 14:'SCd', 15:'HURCl' }"
/>
<xsl:template match="/">
<xsl:iterate select="Journal_Lines/jrnl1">
<xsl:param name="mapJournalLines" as="map(xs:string, element(jrnl1)*)" select="map{}"/>
<xsl:on-completion>
<Journal_Lines>
<!-- Sort data -->
<xsl:for-each select="map:keys($mapJournalLines)">
<xsl:sort select="."/>
<Group CCD="{substring-before(.,'^')}" CC="{substring-after(.,'^')}">
<xsl:for-each select="$mapJournalLines(.)">
<Jrnln>
<xsl:copy-of select="@*"/>
</Jrnln>
</xsl:for-each>
</Group>
</xsl:for-each>
</Journal_Lines>
</xsl:on-completion>
<xsl:variable name="current-entry" select="copy-of()"/>
<xsl:variable name="vKey" as="xs:string" select="$current-entry/@CCD || '^' || $current-entry/@CC"/>
<xsl:next-iteration>
<xsl:with-param name="mapJournalLines"
select="
if (map:contains($mapJournalLines, $vKey)) then
map:put($mapJournalLines, $vKey, ($mapJournalLines($vKey), $current-entry))
else
map:put($mapJournalLines, $vKey, $current-entry)"
/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
最后,为了保持字符串数据映射的原始方法,但为了避免所有的连接和标记化,您可以尝试 map(xs:string, array(xs:string)*)
,即将每组数据存储为序列的映射字符串数组,其中每个数组代表最终输出中的一行:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:output indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:variable name="vElementMap" as="map(*)"
select="map {
1:'CY', 2:'CCD', 3:'CC', 4:'IsPyJrl', 5:'AID',
6:'LAI', 7:'TLCCr', 8:'TCAmt', 9:'TDAmt', 10:'CDI',
11:'CDAmt', 12:'DN', 13:'EDt', 14:'SCd', 15:'HURCl' }"
/>
<xsl:template match="/">
<xsl:iterate select="Journal_Lines/jrnl1">
<xsl:param name="mapJournalLines" as="map(xs:string, array(xs:string)*)" select="map{}"/>
<xsl:on-completion>
<Journal_Lines>
<!-- Sort data -->
<xsl:for-each select="map:keys($mapJournalLines)">
<xsl:sort select="."/>
<Group CCD="{substring-before(.,'^')}" CC="{substring-after(.,'^')}">
<xsl:for-each select="$mapJournalLines(.)">
<Jrnln>
<xsl:for-each select="?*">
<xsl:attribute name="{$vElementMap(position())}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
</Jrnln>
</xsl:for-each>
</Group>
</xsl:for-each>
</Journal_Lines>
</xsl:on-completion>
<xsl:variable name="vKey" as="xs:string" select="@CCD || '^' || @CC"/>
<xsl:variable name="vValue" as="array(xs:string)*" select="array { @*!string() }"/>
<xsl:next-iteration>
<xsl:with-param name="mapJournalLines"
select="
if (map:contains($mapJournalLines, $vKey)) then
map:put($mapJournalLines, $vKey, ($mapJournalLines($vKey), $vValue))
else
map:put($mapJournalLines, $vKey, $vValue)"
/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>