XSLT 3.0 中映射和查找的使用
Use of Maps and Lookups in XSLT 3.0
我是 XSLT 3.0 的新手,我正在探索 xslt 映射和累加器以满足我的一项要求。我有一个输入汇总 XML 如下:
<?xml version="1.0" encoding="UTF-8"?>
<Aggregate>
<File>
<Info>
<emplid>0081781</emplid>
<Number>12345_A</Number>
</Info>
<Info>
<emplid>009892</emplid>
<Number>12345_B</Number>
</Info>
<Info>
<emplid>0044371</emplid>
<Number>12345_C</Number>
</Info>
</File>
<Employee_Data>
<Employee>
<emplid>0081781</emplid>
<empl_Status>A</empl_Status>
</Employee>
<Employee>
<emplid>009892</emplid>
<empl_Status>T</empl_Status>
</Employee>
</Employee_Data>
</Aggregate>
预期结果:
<Root>
<Output_Data>
<Employee>
<emplid>0081781</emplid>
<empl_Status>A</empl_Status>
<Number>12345_A</Number>
</Employee>
<Employee>
<emplid>009892</emplid>
<empl_Status>T</empl_Status>
<Number>12345_B</Number>
</Employee>
</Output_Data>
</Root>
尽管这看起来像是一个相当简单的基于 xsl:key 的 <File>
元素解决方案,但我希望找到一个使用 XSLT 3.0 的流式解决方案,因为数据量非常大,而且我想避免在我的环境中消耗大量内存。
感谢任何帮助!
据我所知,只有 Saxon EE 支持带流式传输的 XSLT 3,因此您可以轻松地使用扩展程序在流式传输期间捕获节点:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 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"
xmlns:saxon="http://saxon.sf.net/"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes" use-accumulators="infos"/>
<xsl:accumulator name="infos" as="map(xs:string, xs:string)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule saxon:capture="yes" phase="end"
match="Info"
select="map:put($value, string(emplid), string(Number))"/>
</xsl:accumulator>
<xsl:template match="File"/>
<xsl:template match="Aggregate">
<Root>
<xsl:apply-templates/>
</Root>
</xsl:template>
<xsl:template match="Employee_Data">
<Output_Data>
<xsl:apply-templates/>
</Output_Data>
</xsl:template>
<xsl:template match="Employee">
<xsl:apply-templates select="copy-of()" mode="burst"/>
</xsl:template>
<xsl:mode name="burst" on-no-match="shallow-copy"/>
<xsl:template match="Employee" mode="burst">
<xsl:copy>
<xsl:apply-templates/>
<Number>{accumulator-before('infos')(string(emplid))}</Number>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
不过,我不确定 saxon:capture
机制是在哪个版本(Saxon EE 的 9.9 或 10)中引入的。
要在没有 Saxon 扩展的情况下做到这一点,我会使用两个累加器,一个用于存储 ID,第二个用于构建地图:
<xsl:accumulator name="emp-id" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="file/Info/emplid/text()" select="normalize-space()"/>
</xsl:accumulator>
<xsl:accumulator name="Employees" as="map(xs:string,xs:string)" streamable="yes" initial-value="map{}">
<xsl:accumulator-rule match="file/Info/Number/text()" select="map:put($value, accumulator-before('emp-id'), normalize-space())"/>
</xsl:accumulator>
我是 XSLT 3.0 的新手,我正在探索 xslt 映射和累加器以满足我的一项要求。我有一个输入汇总 XML 如下:
<?xml version="1.0" encoding="UTF-8"?>
<Aggregate>
<File>
<Info>
<emplid>0081781</emplid>
<Number>12345_A</Number>
</Info>
<Info>
<emplid>009892</emplid>
<Number>12345_B</Number>
</Info>
<Info>
<emplid>0044371</emplid>
<Number>12345_C</Number>
</Info>
</File>
<Employee_Data>
<Employee>
<emplid>0081781</emplid>
<empl_Status>A</empl_Status>
</Employee>
<Employee>
<emplid>009892</emplid>
<empl_Status>T</empl_Status>
</Employee>
</Employee_Data>
</Aggregate>
预期结果:
<Root>
<Output_Data>
<Employee>
<emplid>0081781</emplid>
<empl_Status>A</empl_Status>
<Number>12345_A</Number>
</Employee>
<Employee>
<emplid>009892</emplid>
<empl_Status>T</empl_Status>
<Number>12345_B</Number>
</Employee>
</Output_Data>
</Root>
尽管这看起来像是一个相当简单的基于 xsl:key 的 <File>
元素解决方案,但我希望找到一个使用 XSLT 3.0 的流式解决方案,因为数据量非常大,而且我想避免在我的环境中消耗大量内存。
感谢任何帮助!
据我所知,只有 Saxon EE 支持带流式传输的 XSLT 3,因此您可以轻松地使用扩展程序在流式传输期间捕获节点:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 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"
xmlns:saxon="http://saxon.sf.net/"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes" use-accumulators="infos"/>
<xsl:accumulator name="infos" as="map(xs:string, xs:string)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule saxon:capture="yes" phase="end"
match="Info"
select="map:put($value, string(emplid), string(Number))"/>
</xsl:accumulator>
<xsl:template match="File"/>
<xsl:template match="Aggregate">
<Root>
<xsl:apply-templates/>
</Root>
</xsl:template>
<xsl:template match="Employee_Data">
<Output_Data>
<xsl:apply-templates/>
</Output_Data>
</xsl:template>
<xsl:template match="Employee">
<xsl:apply-templates select="copy-of()" mode="burst"/>
</xsl:template>
<xsl:mode name="burst" on-no-match="shallow-copy"/>
<xsl:template match="Employee" mode="burst">
<xsl:copy>
<xsl:apply-templates/>
<Number>{accumulator-before('infos')(string(emplid))}</Number>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
不过,我不确定 saxon:capture
机制是在哪个版本(Saxon EE 的 9.9 或 10)中引入的。
要在没有 Saxon 扩展的情况下做到这一点,我会使用两个累加器,一个用于存储 ID,第二个用于构建地图:
<xsl:accumulator name="emp-id" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="file/Info/emplid/text()" select="normalize-space()"/>
</xsl:accumulator>
<xsl:accumulator name="Employees" as="map(xs:string,xs:string)" streamable="yes" initial-value="map{}">
<xsl:accumulator-rule match="file/Info/Number/text()" select="map:put($value, accumulator-before('emp-id'), normalize-space())"/>
</xsl:accumulator>