如何修复 XSLT 3.0 地图问题?
how to fix the XSLT 3.0 maps issue?
我正在将一个 XML 文件作为输入,其中包含员工数据和映射值,即 Job Family Id 和 Job Family Name。因此,当员工具有匹配的 Job Family Id 时,我们将替换 Worker_Data 中的 Job Family 名称,并且 Worker_Data 中的其余元素相同。所以我使用了Identity匹配,然后调用需要替换值的元素。但它给了我职位家族名称的空白。
我已尝试使用以下 XSLT 代码来创建地图,并为工作族 ID 匹配调用相同的代码。它只是给我空白。不清楚我错过了什么。如果你们中的任何人能给我一个提示,告诉我哪里出了问题,那将对我很有帮助。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wd="urn:com.workday/bsvc" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="no" on-no-match="shallow-skip" use- accumulators="JobFamilyLookup CurrentLookupValue" />
<xsl:output method="xml" />
<xsl:accumulator name="CurrentLookupValue" as="xs:string" initial- value="''" streamable="no">
<xsl:accumulator-rule match="wd:JobFamilyID/text()" select="string()" />
</xsl:accumulator>
<xsl:accumulator name="JobFamilyLookup" as="map(xs:string,xs:string)" initial-value="map{}" streamable="no">
<xsl:accumulator-rule match="wd:JobFamilyName/text()" select="map:put($value, accumulator-
before('CurrentLookupValue'),string(.))" />
</xsl:accumulator>
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="wd:Job_Family_ID">
<xsl:copy>
<xsl:value-of select="accumulator-before('JobFamilyLookup') (
normalize-space( wd:Job_Family_ID ) )" />
</xsl:copy>
</xsl:template>
<xsl:template match="wd:JobFamilyGroupDetails">
</xsl:template>
</xsl:stylesheet>
输入:
<?xml version="1.0" encoding="UTF-8"?>
<wd:test xmlns:wd="urn:com.workday/bsvc">
<wd:Worker_Data>
<wd:EmpID>50001</wd:EmpID>
<wd:Job_Title>Global Talent Director</wd:Job_Title>
<wd:Job_Family_ID>TAL_TALENT_ACQUISITION</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:Worker_Data>
<wd:EmpID>50000</wd:EmpID>
<wd:Job_Title>Executive Assistant</wd:Job_Title>
<wd:Job_Family_ID>ADMIN_EXECUTIVE_ASSISTANT</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:JobFamilyGroupDetails>
<wd:JobFamilyDetails>
<wd:JobFamilyID>ADMIN_EXECUTIVE_ASSISTANT</wd:JobFamilyID>
<wd:JobFamilyName>ADMIN - Executive Assistant</wd:JobFamilyName>
</wd:JobFamilyDetails>
<wd:JobFamilyDetails>
<wd:JobFamilyID>TAL_TALENT_ACQUISITION</wd:JobFamilyID>
<wd:JobFamilyName>TAL - Talent Acquisition</wd:JobFamilyName>
</wd:JobFamilyDetails>
</wd:JobFamilyGroupDetails>
</wd:test>
预期输出:
<?xml version="1.0" encoding="UTF-8"?>
<wd:test xmlns:wd="urn:com.workday/bsvc">
<wd:Worker_Data>
<wd:EmpID>50001</wd:EmpID>
<wd:Job_Title>Global Talent Director</wd:Job_Title>
<wd:Job_Family_ID>TAL - Talent Acquisition</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:Worker_Data>
<wd:EmpID>50000</wd:EmpID>
<wd:Job_Title>Executive Assistant</wd:Job_Title>
<wd:Job_Family_ID>ADMIN - Executive Assistant</wd:Job_Family_ID>
</wd:Worker_Data>
</wd:test>
我会简单地使用一个密钥:
<?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"
xpath-default-namespace="urn:com.workday/bsvc"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:key name="details" match="JobFamilyDetails" use="JobFamilyID"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="Worker_Data/Job_Family_ID[key('details', .)]">
<xsl:copy>{key('details', .)/JobFamilyName}</xsl:copy>
</xsl:template>
<xsl:template match="JobFamilyGroupDetails"/>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/ncdD7mJ
至于您关于使用流和累加器的请求,因为流向前工作,唯一解决该问题的方法是将相关工作人员数据存储在一系列地图中,然后再在地图中捕获详细数据当您尝试将它用作输出相关元素的工作数据映射序列中每个项目的模板中的参数时:
<?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:wd="urn:com.workday/bsvc"
xpath-default-namespace="urn:com.workday/bsvc"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-skip" streamable="yes" use-accumulators="#all"/>
<xsl:output method="xml" indent="yes"/>
<xsl:accumulator name="current-id" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="JobFamilyDetails/JobFamilyID/text()"
select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="details" as="map(xs:string, xs:string)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule match="JobFamilyDetails/JobFamilyName/text()"
select="map:put($value, accumulator-before('current-id'), string())"/>
</xsl:accumulator>
<xsl:accumulator name="workers" as="map(xs:string, xs:string)*" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="Worker_Data" select="$value, map { }"/>
<xsl:accumulator-rule match="Worker_Data/EmpID/text()"
select="let $wmap := $value[last()]
return ($value[position() lt last()], map:put($wmap, 'id', string()))"/>
<xsl:accumulator-rule match="Worker_Data/Job_Title/text()"
select="let $wmap := $value[last()]
return ($value[position() lt last()], map:put($wmap, 'title', string()))"/>
<xsl:accumulator-rule match="Worker_Data/Job_Family_ID/text()"
select="let $wmap := $value[last()]
return ($value[position() lt last()], map:put($wmap, 'jfid', string()))"/>
</xsl:accumulator>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates/>
<xsl:apply-templates select="accumulator-after('workers')" mode="output">
<xsl:with-param name="details" select="accumulator-after('details')"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match=".[. instance of map(*)]" mode="output" expand-text="yes">
<xsl:param name="details"/>
<wd:Worker_Data>
<wd:EmpID>{?id}</wd:EmpID>
<wd:Job_Title>{?title}</wd:Job_Title>
<wd:Job_Family_ID>{$details(?jfid)}</wd:Job_Family_ID>
</wd:Worker_Data>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/pPzifpL/2
在内存使用方面是否表现良好我还没有测试过。
我正在将一个 XML 文件作为输入,其中包含员工数据和映射值,即 Job Family Id 和 Job Family Name。因此,当员工具有匹配的 Job Family Id 时,我们将替换 Worker_Data 中的 Job Family 名称,并且 Worker_Data 中的其余元素相同。所以我使用了Identity匹配,然后调用需要替换值的元素。但它给了我职位家族名称的空白。
我已尝试使用以下 XSLT 代码来创建地图,并为工作族 ID 匹配调用相同的代码。它只是给我空白。不清楚我错过了什么。如果你们中的任何人能给我一个提示,告诉我哪里出了问题,那将对我很有帮助。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wd="urn:com.workday/bsvc" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="no" on-no-match="shallow-skip" use- accumulators="JobFamilyLookup CurrentLookupValue" />
<xsl:output method="xml" />
<xsl:accumulator name="CurrentLookupValue" as="xs:string" initial- value="''" streamable="no">
<xsl:accumulator-rule match="wd:JobFamilyID/text()" select="string()" />
</xsl:accumulator>
<xsl:accumulator name="JobFamilyLookup" as="map(xs:string,xs:string)" initial-value="map{}" streamable="no">
<xsl:accumulator-rule match="wd:JobFamilyName/text()" select="map:put($value, accumulator-
before('CurrentLookupValue'),string(.))" />
</xsl:accumulator>
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="wd:Job_Family_ID">
<xsl:copy>
<xsl:value-of select="accumulator-before('JobFamilyLookup') (
normalize-space( wd:Job_Family_ID ) )" />
</xsl:copy>
</xsl:template>
<xsl:template match="wd:JobFamilyGroupDetails">
</xsl:template>
</xsl:stylesheet>
输入:
<?xml version="1.0" encoding="UTF-8"?>
<wd:test xmlns:wd="urn:com.workday/bsvc">
<wd:Worker_Data>
<wd:EmpID>50001</wd:EmpID>
<wd:Job_Title>Global Talent Director</wd:Job_Title>
<wd:Job_Family_ID>TAL_TALENT_ACQUISITION</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:Worker_Data>
<wd:EmpID>50000</wd:EmpID>
<wd:Job_Title>Executive Assistant</wd:Job_Title>
<wd:Job_Family_ID>ADMIN_EXECUTIVE_ASSISTANT</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:JobFamilyGroupDetails>
<wd:JobFamilyDetails>
<wd:JobFamilyID>ADMIN_EXECUTIVE_ASSISTANT</wd:JobFamilyID>
<wd:JobFamilyName>ADMIN - Executive Assistant</wd:JobFamilyName>
</wd:JobFamilyDetails>
<wd:JobFamilyDetails>
<wd:JobFamilyID>TAL_TALENT_ACQUISITION</wd:JobFamilyID>
<wd:JobFamilyName>TAL - Talent Acquisition</wd:JobFamilyName>
</wd:JobFamilyDetails>
</wd:JobFamilyGroupDetails>
</wd:test>
预期输出:
<?xml version="1.0" encoding="UTF-8"?>
<wd:test xmlns:wd="urn:com.workday/bsvc">
<wd:Worker_Data>
<wd:EmpID>50001</wd:EmpID>
<wd:Job_Title>Global Talent Director</wd:Job_Title>
<wd:Job_Family_ID>TAL - Talent Acquisition</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:Worker_Data>
<wd:EmpID>50000</wd:EmpID>
<wd:Job_Title>Executive Assistant</wd:Job_Title>
<wd:Job_Family_ID>ADMIN - Executive Assistant</wd:Job_Family_ID>
</wd:Worker_Data>
</wd:test>
我会简单地使用一个密钥:
<?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"
xpath-default-namespace="urn:com.workday/bsvc"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:key name="details" match="JobFamilyDetails" use="JobFamilyID"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="Worker_Data/Job_Family_ID[key('details', .)]">
<xsl:copy>{key('details', .)/JobFamilyName}</xsl:copy>
</xsl:template>
<xsl:template match="JobFamilyGroupDetails"/>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/ncdD7mJ
至于您关于使用流和累加器的请求,因为流向前工作,唯一解决该问题的方法是将相关工作人员数据存储在一系列地图中,然后再在地图中捕获详细数据当您尝试将它用作输出相关元素的工作数据映射序列中每个项目的模板中的参数时:
<?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:wd="urn:com.workday/bsvc"
xpath-default-namespace="urn:com.workday/bsvc"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-skip" streamable="yes" use-accumulators="#all"/>
<xsl:output method="xml" indent="yes"/>
<xsl:accumulator name="current-id" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="JobFamilyDetails/JobFamilyID/text()"
select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="details" as="map(xs:string, xs:string)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule match="JobFamilyDetails/JobFamilyName/text()"
select="map:put($value, accumulator-before('current-id'), string())"/>
</xsl:accumulator>
<xsl:accumulator name="workers" as="map(xs:string, xs:string)*" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="Worker_Data" select="$value, map { }"/>
<xsl:accumulator-rule match="Worker_Data/EmpID/text()"
select="let $wmap := $value[last()]
return ($value[position() lt last()], map:put($wmap, 'id', string()))"/>
<xsl:accumulator-rule match="Worker_Data/Job_Title/text()"
select="let $wmap := $value[last()]
return ($value[position() lt last()], map:put($wmap, 'title', string()))"/>
<xsl:accumulator-rule match="Worker_Data/Job_Family_ID/text()"
select="let $wmap := $value[last()]
return ($value[position() lt last()], map:put($wmap, 'jfid', string()))"/>
</xsl:accumulator>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates/>
<xsl:apply-templates select="accumulator-after('workers')" mode="output">
<xsl:with-param name="details" select="accumulator-after('details')"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match=".[. instance of map(*)]" mode="output" expand-text="yes">
<xsl:param name="details"/>
<wd:Worker_Data>
<wd:EmpID>{?id}</wd:EmpID>
<wd:Job_Title>{?title}</wd:Job_Title>
<wd:Job_Family_ID>{$details(?jfid)}</wd:Job_Family_ID>
</wd:Worker_Data>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/pPzifpL/2
在内存使用方面是否表现良好我还没有测试过。