如何只匹配一次xslt中的节点并将其过滤掉
How to match nodes in xslt only once and filter them out
我有一个包含两种“期刊来源”的文件。下面是一个小示例文件
<File>
<Record>
<employee>935388</employee>
<journal_source>Procurement_Card_Transaction_Verification</journal_source>
<amount>26.31</amount>
<wid>123</wid>
<concat_values>935388|Procurement_Card_Transaction_Verification|26.31</concat_values>
<Created_Moment>2020-12-31T20:45:45.415-08:00</Created_Moment>
<Accounting_Date>2020-12-31-08:00</Accounting_Date>
</Record>
<Record>
<employee>935388</employee>
<journal_source>Credit_Card_Transaction_Load</journal_source>
<amount>-26.31</amount>
<wid>abc</wid>
<concat_values>935388|Credit_Card_Transaction_Load|26.31</concat_values>
<Created_Moment>2020-12-20T20:45:45.415-08:00</Created_Moment>
<Accounting_Date>2020-12-31-08:00</Accounting_Date>
</Record>
<Record>
<employee>935388</employee>
<journal_source>Credit_Card_Transaction_Load</journal_source>
<amount>-26.31</amount>
<wid>def</wid>
<concat_values>935388|Credit_Card_Transaction_Load|26.31</concat_values>
<Created_Moment>2020-12-20T20:45:45.415-08:00</Created_Moment>
<Accounting_Date>2020-12-31-08:00</Accounting_Date>
</Record>
</File>
目标是仅输出具有 journal_source 类型“Credit_Card_Transaction_Load”且没有匹配“Procurement_Card_Transaction_Verification”且也具有“[=27=”的节点]”大于信用卡交易。通过匹配,我的意思是它们对“concat_values”字段具有相同的值,除了一个是 Credit,另一个是 Procurement。
这里棘手的部分是我只能匹配一次采购交易。使用后,即使它们也匹配,我也无法将其用于其他信用卡交易。下面是一个示例,说明之前提供的示例需要输出什么(只对在输出中获取“wid”字段感兴趣):
<File>
<wid>def</wid>
</File>
我首先想到通过在 foreach 循环中更新映射或变量来跟踪已使用的采购交易。然后我会确保检查该交易之前是否已经用于匹配另一笔信用卡交易。但是,这不起作用,因为变量是不可变的。
我也考虑过探索 XSLT 3 的特性并尝试研究累加器,但我没有取得太大进展。
如有任何帮助,我们将不胜感激!
以下示例将采购交易分组到一个映射中,该映射从将员工编号和绝对金额连接到一系列 Record 元素的字符串键开始,然后将此映射用于信用卡交易的迭代中以查找匹配项,如果存在 none 则输出信用卡交易,对于下一次迭代,匹配项将从所用键的映射值中删除:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:function name="mf:get-key" as="xs:string">
<xsl:param name="record" as="element(Record)"/>
<xsl:sequence select="replace($record/concat_values, '\|[^|]+\|', '|')"/>
</xsl:function>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/File">
<xsl:copy>
<xsl:variable name="procurement-map" as="map(xs:string, element(Record)*)">
<xsl:map>
<xsl:for-each-group
select="Record[journal_source = 'Procurement_Card_Transaction_Verification']"
group-by="mf:get-key(.)">
<xsl:map-entry key="current-grouping-key()" select="current-group()"/>
</xsl:for-each-group>
</xsl:map>
</xsl:variable>
<xsl:iterate select="Record[journal_source = 'Credit_Card_Transaction_Load']">
<xsl:param name="procurement-map" select="$procurement-map"/>
<xsl:variable name="key" select="mf:get-key(.)"/>
<xsl:variable name="match" select="$procurement-map($key)[xs:dateTime(Created_Moment) gt xs:dateTime(current()/Created_Moment)][1]"/>
<xsl:if test="not($match)">
<xsl:copy>
<xsl:copy-of select="wid"/>
</xsl:copy>
</xsl:if>
<xsl:next-iteration>
<xsl:with-param name="procurement-map"
select="if (not($match))
then $procurement-map
else map:put($procurement-map, $key, $procurement-map($key) except $match)"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我有一个包含两种“期刊来源”的文件。下面是一个小示例文件
<File>
<Record>
<employee>935388</employee>
<journal_source>Procurement_Card_Transaction_Verification</journal_source>
<amount>26.31</amount>
<wid>123</wid>
<concat_values>935388|Procurement_Card_Transaction_Verification|26.31</concat_values>
<Created_Moment>2020-12-31T20:45:45.415-08:00</Created_Moment>
<Accounting_Date>2020-12-31-08:00</Accounting_Date>
</Record>
<Record>
<employee>935388</employee>
<journal_source>Credit_Card_Transaction_Load</journal_source>
<amount>-26.31</amount>
<wid>abc</wid>
<concat_values>935388|Credit_Card_Transaction_Load|26.31</concat_values>
<Created_Moment>2020-12-20T20:45:45.415-08:00</Created_Moment>
<Accounting_Date>2020-12-31-08:00</Accounting_Date>
</Record>
<Record>
<employee>935388</employee>
<journal_source>Credit_Card_Transaction_Load</journal_source>
<amount>-26.31</amount>
<wid>def</wid>
<concat_values>935388|Credit_Card_Transaction_Load|26.31</concat_values>
<Created_Moment>2020-12-20T20:45:45.415-08:00</Created_Moment>
<Accounting_Date>2020-12-31-08:00</Accounting_Date>
</Record>
</File>
目标是仅输出具有 journal_source 类型“Credit_Card_Transaction_Load”且没有匹配“Procurement_Card_Transaction_Verification”且也具有“[=27=”的节点]”大于信用卡交易。通过匹配,我的意思是它们对“concat_values”字段具有相同的值,除了一个是 Credit,另一个是 Procurement。
这里棘手的部分是我只能匹配一次采购交易。使用后,即使它们也匹配,我也无法将其用于其他信用卡交易。下面是一个示例,说明之前提供的示例需要输出什么(只对在输出中获取“wid”字段感兴趣):
<File>
<wid>def</wid>
</File>
我首先想到通过在 foreach 循环中更新映射或变量来跟踪已使用的采购交易。然后我会确保检查该交易之前是否已经用于匹配另一笔信用卡交易。但是,这不起作用,因为变量是不可变的。
我也考虑过探索 XSLT 3 的特性并尝试研究累加器,但我没有取得太大进展。
如有任何帮助,我们将不胜感激!
以下示例将采购交易分组到一个映射中,该映射从将员工编号和绝对金额连接到一系列 Record 元素的字符串键开始,然后将此映射用于信用卡交易的迭代中以查找匹配项,如果存在 none 则输出信用卡交易,对于下一次迭代,匹配项将从所用键的映射值中删除:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:function name="mf:get-key" as="xs:string">
<xsl:param name="record" as="element(Record)"/>
<xsl:sequence select="replace($record/concat_values, '\|[^|]+\|', '|')"/>
</xsl:function>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/File">
<xsl:copy>
<xsl:variable name="procurement-map" as="map(xs:string, element(Record)*)">
<xsl:map>
<xsl:for-each-group
select="Record[journal_source = 'Procurement_Card_Transaction_Verification']"
group-by="mf:get-key(.)">
<xsl:map-entry key="current-grouping-key()" select="current-group()"/>
</xsl:for-each-group>
</xsl:map>
</xsl:variable>
<xsl:iterate select="Record[journal_source = 'Credit_Card_Transaction_Load']">
<xsl:param name="procurement-map" select="$procurement-map"/>
<xsl:variable name="key" select="mf:get-key(.)"/>
<xsl:variable name="match" select="$procurement-map($key)[xs:dateTime(Created_Moment) gt xs:dateTime(current()/Created_Moment)][1]"/>
<xsl:if test="not($match)">
<xsl:copy>
<xsl:copy-of select="wid"/>
</xsl:copy>
</xsl:if>
<xsl:next-iteration>
<xsl:with-param name="procurement-map"
select="if (not($match))
then $procurement-map
else map:put($procurement-map, $key, $procurement-map($key) except $match)"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>