如何修复 XSLT 3.0 地图问题?

Posted

技术标签:

【中文标题】如何修复 XSLT 3.0 地图问题?【英文标题】:how to fix the XSLT 3.0 maps issue? 【发布时间】:2019-09-26 09:52:01 【问题描述】:

我将一个 XML 文件作为输入,其中包含员工数据和映射值,即职位族 ID 和职位族名称。因此,当员工具有匹配的 Job Family Id 时,我们将替换 Worker_Data 中的 Job Family 名称,并且 Worker_Data 中的其余元素是相同的。所以我使用了 Identity 匹配,然后调用了需要替换值的元素。但它给了我工作族名称的空白。

我已尝试使用以下 XSLT 代码来创建地图并为 Job Family 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>

【问题讨论】:

【参考方案1】:

我会简单地使用一个键:

<?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

在内存使用方面是否表现良好我没有测试过。

【讨论】:

谢谢你,马丁,我想把这段代码变成流式的。这就是我在 XSLT3.0 中来映射概念的原因。我在上面的 sn-p 中将 Streamable 设置为 no,但是当我将代码放入应用程序时我会打开。很抱歉让你们感到困惑。 流式传输只能向前工作,所以我看不到一种方法,因为您的输入结构中 JobFamilyDetails 存储在 Worker_Data 之后,在处理工作人员数据时使用流式传输访问详细信息.您需要对输入进行两次处理,以便在第一次处理后存储详细信息,并在第二次处理工作人员数据时使用。 感谢马丁的解释。我还在学习 XSLT 并且真的不知道这个 Streaming 工作过程。如果您不介意,请给我推荐一本书或网站来学习和理解 XSLT 3.0 的东西。 好吧,XSLT 3 ***.com/tags/xslt-3.0/info 上的 *** 部分有很多指向规范和材料的链接,一般 XSLT 和 XSLT 2 版本 ***.com/tags/xslt-2.0/info 的部分也有很多,如果你通常是 XSLT 的新手。我不确定是否有专门针对 XSLT 3 的书,但 Saxon 文档中的 Saxonica 处理了与 XSLT 和 XPath saxonica.com/html/documentation/using-xsl/xslt30.html 相关的所有内容。另一家供应商 Altova 也有专门介绍 XPath 3 的部分altova.com/training/xpath3。 非常感谢马丁。这肯定会帮助我分配。

以上是关于如何修复 XSLT 3.0 地图问题?的主要内容,如果未能解决你的问题,请参考以下文章

BizTalk 2020 Saxon XSLT 3.0 转换异常

如何在 Spring 3.0 中注入地图类型对象

如何修复站点地图错误?

android开发 百度地图3.0以上版本,如何显示自定义标记图标?

如何修复 PHP XML 站点地图编码错误

如何在 iPhone 上使用 EAS 版本修复 Google 地图错误?