根据子节点的值增加节点的位置
Increment the position of a node based on the value of child node
这是我的来源XML
<?xml version="1.0" encoding="UTF-8"?>
<Workers>
<Worker>
<ID>12345</ID>
<Amount>0.50</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>45678</ID>
<Amount>00.50</Amount>
<CurrentPayments>5</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.20</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.50</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
</Workers>
Worker
和 ID
值 12345
在源文件中出现三次,具有相同的 CurrentPayments
值,即 2
转换上述文件后,CurrentPayments
的位置值应根据元素 CurrentPayments
在源文件中出现的次数递增。
在这种情况下,ID
值 12345
的 Worker
的第一次出现应该具有 CurrentPayments
值 3(即 CurrentPayments
的值源 xml 是 2 递增 1 - Worker
第一次出现 ID
值 12345
)
第二次出现 ID
值 12345
的 Worker
应具有 CurrentPayments
值 4(即 CurrentPayments
在源 [=90 上的值=] 是 2 递增 2 - Worker
第二次出现 ID
值 12345
)
具有 ID
值 12345
的 Worker
第三次出现的 CurrentPayments
值应为 5(即源 [=90 上 CurrentPayments
的值=] 是 2 递增 3 - Worker
第三次出现 ID
值 12345
)
期望的输出如下。
<?xml version="1.0" encoding="UTF-8"?>
<Workers>
<Worker>
<ID>12345</ID>
<Amount>0.50</Amount>
<CurrentPayments>3</CurrentPayments>
</Worker>
<Worker>
<ID>45678</ID>
<Amount>00.50</Amount>
<CurrentPayments>6</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.20</Amount>
<CurrentPayments>4</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.50</Amount>
<CurrentPayments>5</CurrentPayments>
</Worker>
</Workers>
我尝试使用 position()
,使用 xpath 轴等将当前节点的值与同一元素的子节点进行比较。 <xsl:value-of select="count(//.[(following::text() = text())])+position()"/>
这是我当前的 XSLT
<?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" exclude-result-prefixes="xs" version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="CurrentPayments">
<xsl:for-each select=".">
<CurrentPayments>
<xsl:value-of select=".+ position()"/>
</CurrentPayments>
<!--<CurrentPayments>
<xsl:value-of select="count(//.[(following::text() = text())])+position()"/>
</CurrentPayments> -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
你能告诉我如何让它工作吗?谢谢
下面添加
Martin Honnen 的 XSLT 3.0 解决方案非常适合上述要求。但是,我注意到 CurrentPayments
可能不会对所有 <Worker>
都存在。在这种情况下,源 XML 看起来像这样(<Worker>
的最后一个节点 ID
123458
没有 CurrentPayments
并且预期的输出应该有元素 CurrentPayments
创建的值 1
<?xml version="1.0" encoding="UTF-8"?>
<Workers>
<Worker>
<ID>12345</ID>
<Amount>0.50</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>45678</ID>
<Amount>00.50</Amount>
<CurrentPayments>5</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.20</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.50</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>123458</ID>
<Amount>00.50</Amount>
</Worker>
</Workers>
我添加了一个新模板 <xsl:template match="Worker[not(CurrentPayments)]">
以创建具有值 1
的元素 CurrentPayments
。你能告诉我这是否是我唯一的选择吗?
<?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"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:accumulator name="worker-count" as="map(xs:integer, xs:integer)" initial-value="map{}">
<xsl:accumulator-rule match="Worker/ID"
select="let $id := xs:integer(.)
return
if (map:contains($value, $id))
then map:put($value, $id, $value($id) + 1)
else map:put($value, $id, 1)"/>
</xsl:accumulator>
<xsl:mode on-no-match="shallow-copy" use-accumulators="worker-count"/>
<xsl:template match="CurrentPayments">
<xsl:choose>
<xsl:when test=".!=''">
<xsl:copy>{. + accumulator-before('worker-count')(xs:integer(../ID))}</xsl:copy>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Worker[not(CurrentPayments)]">
<xsl:copy>
<xsl:apply-templates/>
<CurrentPayments>1</CurrentPayments>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
对于 XSLT 3,我认为这是累加器的任务:
<?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"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:accumulator name="worker-count" as="map(xs:integer, xs:integer)" initial-value="map{}">
<xsl:accumulator-rule match="Worker/ID"
select="let $id := xs:integer(.)
return
if (map:contains($value, $id))
then map:put($value, $id, $value($id) + 1)
else map:put($value, $id, 1)"/>
</xsl:accumulator>
<xsl:mode on-no-match="shallow-copy" use-accumulators="worker-count"/>
<xsl:template match="CurrentPayments">
<xsl:copy>{. + accumulator-before('worker-count')(xs:integer(../ID))}</xsl:copy>
</xsl:template>
</xsl:stylesheet>
在该代码示例中,累加器在映射中存储 Worker
的 ID
加上 Worker
的出现次数,CurrentPayments
的规则然后可以简单地访问累加器。
这是我的来源XML
<?xml version="1.0" encoding="UTF-8"?>
<Workers>
<Worker>
<ID>12345</ID>
<Amount>0.50</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>45678</ID>
<Amount>00.50</Amount>
<CurrentPayments>5</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.20</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.50</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
</Workers>
Worker
和ID
值12345
在源文件中出现三次,具有相同的CurrentPayments
值,即2
转换上述文件后,CurrentPayments
的位置值应根据元素 CurrentPayments
在源文件中出现的次数递增。
在这种情况下,ID
值 12345
的 Worker
的第一次出现应该具有 CurrentPayments
值 3(即 CurrentPayments
的值源 xml 是 2 递增 1 - Worker
第一次出现 ID
值 12345
)
第二次出现 ID
值 12345
的 Worker
应具有 CurrentPayments
值 4(即 CurrentPayments
在源 [=90 上的值=] 是 2 递增 2 - Worker
第二次出现 ID
值 12345
)
具有 ID
值 12345
的 Worker
第三次出现的 CurrentPayments
值应为 5(即源 [=90 上 CurrentPayments
的值=] 是 2 递增 3 - Worker
第三次出现 ID
值 12345
)
期望的输出如下。
<?xml version="1.0" encoding="UTF-8"?>
<Workers>
<Worker>
<ID>12345</ID>
<Amount>0.50</Amount>
<CurrentPayments>3</CurrentPayments>
</Worker>
<Worker>
<ID>45678</ID>
<Amount>00.50</Amount>
<CurrentPayments>6</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.20</Amount>
<CurrentPayments>4</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.50</Amount>
<CurrentPayments>5</CurrentPayments>
</Worker>
</Workers>
我尝试使用 position()
,使用 xpath 轴等将当前节点的值与同一元素的子节点进行比较。 <xsl:value-of select="count(//.[(following::text() = text())])+position()"/>
这是我当前的 XSLT
<?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" exclude-result-prefixes="xs" version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="CurrentPayments">
<xsl:for-each select=".">
<CurrentPayments>
<xsl:value-of select=".+ position()"/>
</CurrentPayments>
<!--<CurrentPayments>
<xsl:value-of select="count(//.[(following::text() = text())])+position()"/>
</CurrentPayments> -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
你能告诉我如何让它工作吗?谢谢
下面添加
Martin Honnen 的 XSLT 3.0 解决方案非常适合上述要求。但是,我注意到 CurrentPayments
可能不会对所有 <Worker>
都存在。在这种情况下,源 XML 看起来像这样(<Worker>
的最后一个节点 ID
123458
没有 CurrentPayments
并且预期的输出应该有元素 CurrentPayments
创建的值 1
<?xml version="1.0" encoding="UTF-8"?>
<Workers>
<Worker>
<ID>12345</ID>
<Amount>0.50</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>45678</ID>
<Amount>00.50</Amount>
<CurrentPayments>5</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.20</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>12345</ID>
<Amount>00.50</Amount>
<CurrentPayments>2</CurrentPayments>
</Worker>
<Worker>
<ID>123458</ID>
<Amount>00.50</Amount>
</Worker>
</Workers>
我添加了一个新模板 <xsl:template match="Worker[not(CurrentPayments)]">
以创建具有值 1
的元素 CurrentPayments
。你能告诉我这是否是我唯一的选择吗?
<?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"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:accumulator name="worker-count" as="map(xs:integer, xs:integer)" initial-value="map{}">
<xsl:accumulator-rule match="Worker/ID"
select="let $id := xs:integer(.)
return
if (map:contains($value, $id))
then map:put($value, $id, $value($id) + 1)
else map:put($value, $id, 1)"/>
</xsl:accumulator>
<xsl:mode on-no-match="shallow-copy" use-accumulators="worker-count"/>
<xsl:template match="CurrentPayments">
<xsl:choose>
<xsl:when test=".!=''">
<xsl:copy>{. + accumulator-before('worker-count')(xs:integer(../ID))}</xsl:copy>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Worker[not(CurrentPayments)]">
<xsl:copy>
<xsl:apply-templates/>
<CurrentPayments>1</CurrentPayments>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
对于 XSLT 3,我认为这是累加器的任务:
<?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"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:accumulator name="worker-count" as="map(xs:integer, xs:integer)" initial-value="map{}">
<xsl:accumulator-rule match="Worker/ID"
select="let $id := xs:integer(.)
return
if (map:contains($value, $id))
then map:put($value, $id, $value($id) + 1)
else map:put($value, $id, 1)"/>
</xsl:accumulator>
<xsl:mode on-no-match="shallow-copy" use-accumulators="worker-count"/>
<xsl:template match="CurrentPayments">
<xsl:copy>{. + accumulator-before('worker-count')(xs:integer(../ID))}</xsl:copy>
</xsl:template>
</xsl:stylesheet>
在该代码示例中,累加器在映射中存储 Worker
的 ID
加上 Worker
的出现次数,CurrentPayments
的规则然后可以简单地访问累加器。