#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>
Ответ №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