【问题标题】:Mapping Values Using XSL 3.0 accumulators使用 XSL 3.0 累加器映射值
【发布时间】:2022-06-10 18:32:01
【问题描述】:

我需要使用 xsl 3.0 累加器将以下 xml 转换为 预期输出

输入 XML:

<AggregatedData>
   <Data>
      <Entry>
         <legacyID>ABC</legacyID>
         <legacyLocation>Test_Loc1,Test_Loc2</legacyLocation>
         <AssociateID>123</AssociateID>
      </Entry>
      <Entry>
         <legacyID>ABC</legacyID>
         <legacyLocation>Test_Loc3</legacyLocation>
         <AssociateID>123</AssociateID>
      </Entry>
      <Entry>
         <legacyID>CDE</legacyID>
         <legacyLocation>Test_Loc4,Test_Loc5</legacyLocation>
         <AssociateID>456</AssociateID>
      </Entry>
   </Data>
   <root>
      <row>
         <legacyID>ABC</legacyID>
         <legacyLocation>Test_Loc1</legacyLocation>
         <company>Test Company 1</company>
         <firstname>Test1</firstname>
      </row>
      <row>
         <legacyID>CDE</legacyID>
         <legacyLocation>Test_Loc5</legacyLocation>
         <company>Test Company 2</company>
         <firstname>Test2</firstname>
      </row>
   </root>
</AggregatedData>

&lt;Data&gt; 下的值可以包含&lt;legacyLocation&gt; 的逗号分隔值,&lt;root&gt; 下的值仅包含一个&lt;legacyLocation&gt; 的值。我需要映射这些值并将输出作为下面的预期输出。有没有办法使用 XSLT 3.0 累加器同时使用 legacyIDlegacyLocation 来映射值?

预期输出:

<root>
   <worker>
      <row>
         <AssociateID>123</AssociateID>
         <legacyID>ABC</legacyID>
         <legacyLocation>Test_Loc1</legacyLocation>
         <company>Test Company 1</company>
         <firstname>Test1</firstname>
      </row>
      <row>
         <AssociateID>456</AssociateID>
         <legacyID>CDE</legacyID>
         <legacyLocation>Test_Loc5</legacyLocation>
         <company>Test Company 2</company>
         <firstname>Test2</firstname>
      </row>
   </worker>
</root>

【问题讨论】:

  • 你试过什么?为什么需要使用累加器而不是键?
  • @MartinHonnen 以前的要求是仅使用 legacyID 进行映射,但就示例而言,它不是唯一值。映射速度是使用累加器的原因。因为有将近 4000 多条记录。
  • CDETest_Loc4,Test_Loc5,Test_Loc6456CDETest_Loc5Test Company 2Test2 AggregatedData> 当我们尝试匹配 legacyLocation 节点的第一个值时,代码按预期工作。但是当我们需要匹配行数据和条目数据之间的“Test_Loc5”(中间值)时,它没有选择确切的关联 ID。@马丁霍南

标签: xml xslt xslt-3.0 accumulator


【解决方案1】:

我认为你可以使用像这样的键

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">
  
  <xsl:key name="assoc-id" match="Entry" use="(legacyLocation => tokenize(',') => sort()) ! (current()/legacyID || ',' || .)"/>

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:template match="/AggregatedData">
    <xsl:apply-templates select="root"/>
  </xsl:template>

  <xsl:template match="row">
    <xsl:copy>
      <xsl:apply-templates select="key('assoc-id', (legacyID || ',' || legacyLocation))/AssociateID, node()"/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

我不明白为什么累加器会表现得更好,如果您需要与流交叉引用,我主要会尝试使用它。

累加器的非流式使用将是

<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"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">
  
  <xsl:accumulator name="assoc-id" as="map(xs:string, xs:string)" initial-value="map{}">
    <xsl:accumulator-rule 
      match="Entry" 
      select="let $entry := . 
              return fold-left(legacyLocation => tokenize(',') => sort(), $value, function($a, $k) { map:put($a, $entry/legacyID || ',' || $k, $entry/AssociateID/string()) })"/>
  </xsl:accumulator>
  
  <xsl:mode on-no-match="shallow-copy" use-accumulators="assoc-id"/>
  
  <xsl:template match="/AggregatedData">
    <xsl:apply-templates select="root"/>
  </xsl:template>

  <xsl:template match="row">
    <xsl:copy>
      <AssociateID>{accumulator-before('assoc-id')(legacyID || ',' || legacyLocation)}</AssociateID>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-07
    • 2012-05-30
    • 2021-07-29
    • 2011-08-14
    相关资源
    最近更新 更多