Удаление дубликатов элементов в xslt с помощью json в качестве входных данных

#xslt

#xslt

Вопрос:

У меня есть этот json:

 {
    "data": {
        "cc": [            
            {
                "code": "90210",
                "name": "irdf",
                "costUnit": [
                    1,
                    2
                ],
                "description": "",
                "start": "2018-12-01T00:00:00.000Z",
                "end": "2099-12-31T00:00:00.000Z",
                "companies": [
                    {
                        "accountingSystem": {
                            "name": "agr",
                            "prefix": 2
                        }
                    },
                    {
                        "accountingSystem": {
                            "name": "jev",
                            "prefix": 1
                        }
                    },
                    {
                        "accountingSystem": {
                            "name": "agr",
                            "prefix": 2
                        }
                    }
                ]
            }
        ]
    }
}
  

И использовал этот xsl для удаления companies дубликатов элементов:

 <?xml version="1.0"?>
<xsl:stylesheet version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:j="http://www.w3.org/2005/xpath-functions"
  xmlns:exsl="http://exslt.org/common"
  extension-element-prefixes="exsl"
>
  <xsl:output method="text" indent="yes"/>
  <xsl:template match="/file">
    <xsl:variable name="json" select="json-to-xml(.)"/>
    <xsl:call-template name="root">
      <xsl:with-param name="document" select="$json"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="root">
    <xsl:param name="document" />    
    <xsl:for-each select="$document/j:map/j:map/j:array/j:map">
      <xsl:call-template name="row">
        <xsl:with-param name="row" select="."/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="row">
    <xsl:param name="row" />
    <xsl:for-each-group select="$row/*[@key='companies']/*" group-by="$row/*[@key='companies']/j:map">
      <xsl:variable name="company" select="." />
      <xsl:value-of select="$row/*[@key='code']" />-<xsl:value-of select="$company/*[@key='accountingSystem']/*[@key='prefix']" /><xsl:text>amp;#xd;amp;#xa;</xsl:text>      
    </xsl:for-each-group>
  </xsl:template>
</xsl:stylesheet>
  

Когда я запускаю его, я получаю это вместо:

 90210-2
90210-2
  

Обратите внимание, что 90210 отображается дважды, но с тем же префиксом (2)

Я ожидал этого

 90210-1
90210-2
  

Как мне получить ожидаемое?

Ответ №1:

В качестве альтернативы вы также можете работать с JSON, обрабатываемым как карты и массивы XPath 3.1 в XSLT 3:

 <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:output method="text"/>

  <xsl:template match="file">
      <xsl:value-of
         select="let $map := parse-json(.), 
                     $cc := $map?data?cc?*, 
                     $code := $cc?code
                 return sort(distinct-values($cc?companies?*?accountingSystem?prefix))!($code || '-' || .)"
                 separator="amp;#10;"/>
  </xsl:template>

</xsl:stylesheet>
  

https://xsltfiddle .liberty-development.net/pPzifpi/2

Или с помощью группировки:

   <xsl:template match="file">
      <xsl:variable name="json-map" select="parse-json(.)"/>
      <xsl:variable name="cc" select="$json-map?data?cc?*"/>
      <xsl:variable name="code" select="$cc?code"/>
      <xsl:for-each-group select="$cc?companies?*?accountingSystem" group-by="?prefix">
          <xsl:sort select="current-grouping-key()"/>
          <xsl:value-of select="$code, current-grouping-key()" separator="-"/>
          <xsl:text>amp;#10;</xsl:text>
      </xsl:for-each-group>
  </xsl:template>
  

https://xsltfiddle .liberty-development.net/pPzifpi/3

Ответ №2:

Я думаю, что ваш xsl:for-each-group должен выглядеть следующим образом:

 <xsl:for-each-group select="$row/*[@key='companies']/*" group-by="*/*[@key='prefix']">
  <xsl:sort select="current-grouping-key()" />
  <xsl:value-of select="$row/*[@key='code']" />-<xsl:value-of select="current-grouping-key()" /><xsl:text>amp;#xd;amp;#xa;</xsl:text>      
</xsl:for-each-group>
  

Посмотрите это в действии на http://xsltfiddle .liberty-development.net/ej9EGca