我想基于csv文件构建地图。
地图声明:
<xsl:variable name="myMap" as="map(xs:string, array(xs:string))">
Csv文件:
key1;value1
key1;value2
key2;value3
因此,地图应由两个元素组成: key1 =>数组['value1','value2'] key2 =>数组['value3']
我试图创建类似的地图:
<xsl:variable name="myMap" as="map(xs:string, array(xs:string))">
<xsl:map>
<xsl:if test="unparsed-text-available($csv-file, $csv-encoding)">
<xsl:variable name="csv" select="unparsed-text($csv-file, $csv-encoding)"/>
<xsl:analyze-string select="$csv" regex="\r\n?|\n">
<xsl:non-matching-substring>
<xsl:variable name="row" select="tokenize(., '\t')"/>
<xsl:variable name="key" select="$row[1]"/>
<xsl:variable name="array_element" select="$row[2]"/>
<xsl:map-entry key="$key" select="$array_element"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:if>
</xsl:map>
</xsl:variable>
但是我找不到合并地图条目的方法。
我的第二种方法是首先声明map:
<xsl:variable name="myMap" as="map(xs:string, array(xs:string))">
<xsl:map/>
</xsl:variable>
然后我尝试根据这样的csv文件内容填充它:
<xsl:if test="unparsed-text-available($csv-file, $csv-encoding)">
<xsl:variable name="csv" select="unparsed-text($csv-file, $csv-encoding)" />
<xsl:analyze-string select="$csv" regex="\r\n?|\n">
<xsl:non-matching-substring>
<xsl:variable name="row" select="tokenize(., '\t')"/>
<xsl:variable name="key" as="xs:string" select="$row[1]"/>
<xsl:variable name="value" as="xs:string" select="$row[2]"/>
<xsl:choose>
<xsl:when test="map:contains($myMap, $key)">
<xsl:variable name="valueArray" select="map:get($myMap,$key)"/>
<xsl:sequence select="array:append($valueArray, $value)" />
<xsl:sequence select="map:put($myMap, $key, $valueArray) />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="valueArray" as="array(xs:string)" select="[]"/>
<xsl:sequence select="array:append($valueArray, $value)" />
<xsl:sequence select="map:put($myMap, $key, $valueArray) />
</xsl:otherwise>
</xsl:choose>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:if>
是否可以从模板调用array:append和map:put方法?
答案 0 :(得分:0)
我认为,假设您使用XSLT 3,则可以将其视为分组问题,您可以将CSV中的行分组到substring-before(., ';')
上:
<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:param name="csv-string" as="xs:string">key1;value1
key1;value2
key2;value3</xsl:param>
<xsl:variable name="myMap" as="map(xs:string, array(xs:string))">
<xsl:map>
<xsl:for-each-group select="tokenize($csv-string, '\r?\n')[normalize-space()]" group-by="substring-before(., ';')">
<xsl:map-entry key="current-grouping-key()" select="array{ current-group()!tokenize(substring-after(., ';'), ';') }"/>
</xsl:for-each-group>
</xsl:map>
</xsl:variable>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="json" indent="yes" />
<xsl:template match="/" name="xsl:initial-template">
<xsl:sequence select="$myMap"/>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/nc4NzRb
例如,我从CSV内联了内容,但是您也可以使用<xsl:for-each-group select="unparsed-text-lines('file.csv')" group-by="substring-before(., ';')">
来从文件中加载。
对于构建和合并地图,如果不需要array(xs:string)
作为地图值,但可以使用一系列字符串,则可以使用map:merge
函数和一个选项来组合值相同的键:
<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"
version="3.0">
<xsl:param name="csv-string" as="xs:string">key1;value1
key1;value2
key2;value3</xsl:param>
<xsl:variable name="myMap" as="map(xs:string, xs:string*)"
select="map:merge(
tokenize($csv-string, '\r?\n')[normalize-space()]
!
(
let $values := tokenize(., ';')
return map { head($values) : tail($values) }
),
map { 'duplicates' : 'combine' }
)"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="adaptive" indent="yes" />
<xsl:template match="/" name="xsl:initial-template">
<xsl:sequence select="$myMap"/>
</xsl:template>
</xsl:stylesheet>