xslt 3.0 和 xpath3.1 的数组和映射示例
Example of array and map for xslt 3.0 and xpath3.1
我想使用 XPath3.1 中的新功能,如 array
和 map
,这听起来像是一个可通过 google 搜索的问题,但我尝试了很多示例代码仍然收到错误消息,以下是我的方法到目前为止:
<!-- XSLT.xslt -->
<!-- using SaxonHE9-8-0-7 -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="system-property('xsl:version ')"/> <!-- show 3.0 -->
<xsl:copy-of select="system-property('xsl:vendor ')"/> <!-- show Saxonica -->
<xsl:copy-of select="system-property('xsl:xpath-version')"/> <!-- show 3.1 -->
<xsl:copy-of select="system-property('xsl:xsd-version ')"/> <!-- show 1.1 -->
</xsl:template>
</xsl:stylesheet>
所以有一个简单有效的代码可以证明 array
和 map
的强大功能吗?谢谢!
地图主要可以帮助解决两个问题:
- 流式传输,参见 https://www.w3.org/TR/xslt-30/#maps-streaming,尽管在使用 Saxon 9.8 HE 时您不能使用流式传输。
- JSON 处理,因为 JSON 对象可以分别映射到 XSLT 3 XPath 3.1 映射,见 https://www.w3.org/TR/xpath-functions/#json and https://www.w3.org/TR/xslt-30/#json
至于简单的例子,映射和数组语法和函数规范中的各个部分都有简单的例子,要将这些函数与 XSLT 一起使用,您只需确保声明函数在其中定义的命名空间与例如
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
我不确定简单的示例是否可以展示新语言功能的强大功能,映射和数组具有各种功能,举个例子,通过创建将一些 XML 输入转换为 JSON映射(在一个模板中使用 XSLT xsl:map
,在另一个模板中使用 XPath 映射构造函数语法)和数组并将结果序列化为 json
:
<?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:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="xs math map array"
version="3.0">
<xsl:output method="json" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="root">
<xsl:map>
<xsl:map-entry key="local-name()">
<xsl:apply-templates/>
</xsl:map-entry>
</xsl:map>
</xsl:template>
<xsl:template match="items">
<xsl:variable name="items" as="item()*">
<xsl:apply-templates/>
</xsl:variable>
<xsl:sequence select="map { local-name() : array { $items }}"/>
</xsl:template>
<xsl:template match="item">
<xsl:sequence select="map { 'foo' : xs:integer(foo), 'bar' : string(bar) }"/>
</xsl:template>
</xsl:stylesheet>
这样就转变了
<root>
<items>
<item>
<foo>1</foo>
<bar>a</bar>
</item>
<item>
<foo>2</foo>
<bar>b</bar>
</item>
</items>
</root>
到JSON
{
"root": {
"items": [
{
"foo":1,
"bar":"a"
},
{
"foo":2,
"bar":"b"
}
]
}
}
在线 http://xsltfiddle.liberty-development.net/b4GWV3。
我还在 http://xsltfiddle.liberty-development.net/6qM2e27 上整理了另一个示例,其中显示了构建地图的一些方法:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="xs math map array"
version="3.0">
<xsl:output method="adaptive" indent="yes"/>
<!-- a map constructed with XPath 3.1 map constructor https://www.w3.org/TR/xpath-31/#id-map-constructors -->
<xsl:param name="map1" as="map(*)" select="map { 'string' : 'foo', 'number' : 3.14, 'boolean' : true(), 'sequence' : (1, 2, 3) }"/>
<xsl:param name="json-string" as="xs:string">
{
"foo" : "value 1",
"bar" : 3.14,
"baz" : true,
"items" : ["a", "b", "c" ]
}
</xsl:param>
<!-- a map constructed from a string containing JSON using the parse-json function https://www.w3.org/TR/xpath-functions/#func-parse-json -->
<xsl:param name="map2" as="map(*)" select="parse-json($json-string)"/>
<!-- a map constructed using the XSLT xsl:map and xsl:map-entry instructions https://www.w3.org/TR/xslt-30/#map-instructions -->
<xsl:param name="map3" as="map(*)">
<xsl:map>
<xsl:map-entry key="'key1'" select="'value 1'"/>
<xsl:map-entry key="'x'" select="3.1415927"/>
</xsl:map>
</xsl:param>
<!-- a map constructed by merging several maps using the map:merge function https://www.w3.org/TR/xpath-functions/#func-map-merge -->
<xsl:param name="map4" as="map(*)" select="map:merge(($map1, $map2, $map3))"/>
<!-- a map constructed by putting a new value into an existing map using the map:put function https://www.w3.org/TR/xpath-functions/#func-map-put -->
<xsl:param name="map5" as="map(*)" select="map:put($map1, 'new-key', 'new value')"/>
<xsl:template match="/">
<xsl:sequence select="$map1, $map2, $map3, $map4, $map5"/>
</xsl:template>
</xsl:stylesheet>
它的输出是(不幸的是,目前撒克逊人无法使用输出方法 'adaptive' 漂亮地 print/indent 项目):
map{"sequence":(1,2,3),"boolean":true(),"number":3.14,"string":"foo"}
map{"items":["a","b","c"],"foo":"value 1","bar":3.14e0,"baz":true()}
map{"key1":"value 1","x":3.1415927}
map{"items":["a","b","c"],"sequence":(1,2,3),"foo":"value 1","boolean":true(),"number":3.14,"string":"foo","key1":"value 1","bar":3.14e0,"x":3.1415927,"baz":true()}
map{"sequence":(1,2,3),"boolean":true(),"number":3.14,"string":"foo","new-key":"new value"}
显示一些构造数组的基本变体的类似示例是
<?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:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="xs math map array"
version="3.0">
<xsl:output method="adaptive" indent="yes"/>
<!-- array created with square array constructor https://www.w3.org/TR/xpath-31/#prod-xpath31-SquareArrayConstructor -->
<xsl:param name="array1" as="array(xs:integer)" select="[1, 2, 3, 4]"/>
<!-- array created with curly braces array constructor https://www.w3.org/TR/xpath-31/#prod-xpath31-CurlyArrayConstructor -->
<xsl:param name="array2" as="array(xs:string)" select="array{ (string-to-codepoints('A') to string-to-codepoints('E'))!codepoints-to-string(.) }"/>
<!-- if we use the square array constructor with an expression like above inside we get an array containing a sequence of strings -->
<xsl:param name="array3" as="array(xs:string*)" select="[ (string-to-codepoints('A') to string-to-codepoints('E'))!codepoints-to-string(.) ]"/>
<xsl:param name="json-array-as-string" as="xs:string">
[ { "foo" : 1 }, { "foo" : 2 }, { "foo" : 3 } ]
</xsl:param>
<!-- array constructed by parsing JSON input with function parse-json https://www.w3.org/TR/xpath-functions/#func-parse-json -->
<xsl:param name="array4" as="array(map(xs:string, xs:double))" select="parse-json($json-array-as-string)"/>
<!-- array constructed by joining two arrays using the function array:join https://www.w3.org/TR/xpath-functions/#func-array-join -->
<xsl:param name="array5" as="array(*)" select="array:join(($array1, $array2))"/>
<!-- array constructed by extracting subarray with function array:subarray https://www.w3.org/TR/xpath-functions/#func-array-subarray -->
<xsl:param name="array6" as="array(*)" select="array:subarray($array5, 3, 4)"/>
<xsl:template match="/">
<xsl:sequence select="$array1, $array2, $array3, $array4, $array5, $array6"/>
</xsl:template>
</xsl:stylesheet>
输出
[1,2,3,4]
["A","B","C","D","E"]
[("A","B","C","D","E")]
[map{"foo":1.0e0},map{"foo":2.0e0},map{"foo":3.0e0}]
[1,2,3,4,"A","B","C","D","E"]
[3,4,"A","B"]
http://xsltfiddle.liberty-development.net/eiQZDbd
在发布的这个阶段,可能还值得查看 XSLT 3 中的各种测试用例以及组合的 XPath 和 XQuery 测试套件,例如:
- https://dvcs.w3.org/hg/xslt30-test/file/tip/tests/strm/si-map 使用
xsl:map
和流
- https://dvcs.w3.org/hg/xslt30-test/file/tip/tests/fn/xml-to-json 有
xml-to-json
的测试
- https://dvcs.w3.org/hg/xslt30-test/file/tip/tests/fn/json-to-xml 有
json-to-xml
个测试用例。
我想使用 XPath3.1 中的新功能,如 array
和 map
,这听起来像是一个可通过 google 搜索的问题,但我尝试了很多示例代码仍然收到错误消息,以下是我的方法到目前为止:
<!-- XSLT.xslt -->
<!-- using SaxonHE9-8-0-7 -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="system-property('xsl:version ')"/> <!-- show 3.0 -->
<xsl:copy-of select="system-property('xsl:vendor ')"/> <!-- show Saxonica -->
<xsl:copy-of select="system-property('xsl:xpath-version')"/> <!-- show 3.1 -->
<xsl:copy-of select="system-property('xsl:xsd-version ')"/> <!-- show 1.1 -->
</xsl:template>
</xsl:stylesheet>
所以有一个简单有效的代码可以证明 array
和 map
的强大功能吗?谢谢!
地图主要可以帮助解决两个问题:
- 流式传输,参见 https://www.w3.org/TR/xslt-30/#maps-streaming,尽管在使用 Saxon 9.8 HE 时您不能使用流式传输。
- JSON 处理,因为 JSON 对象可以分别映射到 XSLT 3 XPath 3.1 映射,见 https://www.w3.org/TR/xpath-functions/#json and https://www.w3.org/TR/xslt-30/#json
至于简单的例子,映射和数组语法和函数规范中的各个部分都有简单的例子,要将这些函数与 XSLT 一起使用,您只需确保声明函数在其中定义的命名空间与例如
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
我不确定简单的示例是否可以展示新语言功能的强大功能,映射和数组具有各种功能,举个例子,通过创建将一些 XML 输入转换为 JSON映射(在一个模板中使用 XSLT xsl:map
,在另一个模板中使用 XPath 映射构造函数语法)和数组并将结果序列化为 json
:
<?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:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="xs math map array"
version="3.0">
<xsl:output method="json" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="root">
<xsl:map>
<xsl:map-entry key="local-name()">
<xsl:apply-templates/>
</xsl:map-entry>
</xsl:map>
</xsl:template>
<xsl:template match="items">
<xsl:variable name="items" as="item()*">
<xsl:apply-templates/>
</xsl:variable>
<xsl:sequence select="map { local-name() : array { $items }}"/>
</xsl:template>
<xsl:template match="item">
<xsl:sequence select="map { 'foo' : xs:integer(foo), 'bar' : string(bar) }"/>
</xsl:template>
</xsl:stylesheet>
这样就转变了
<root>
<items>
<item>
<foo>1</foo>
<bar>a</bar>
</item>
<item>
<foo>2</foo>
<bar>b</bar>
</item>
</items>
</root>
到JSON
{
"root": {
"items": [
{
"foo":1,
"bar":"a"
},
{
"foo":2,
"bar":"b"
}
]
}
}
在线 http://xsltfiddle.liberty-development.net/b4GWV3。
我还在 http://xsltfiddle.liberty-development.net/6qM2e27 上整理了另一个示例,其中显示了构建地图的一些方法:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="xs math map array"
version="3.0">
<xsl:output method="adaptive" indent="yes"/>
<!-- a map constructed with XPath 3.1 map constructor https://www.w3.org/TR/xpath-31/#id-map-constructors -->
<xsl:param name="map1" as="map(*)" select="map { 'string' : 'foo', 'number' : 3.14, 'boolean' : true(), 'sequence' : (1, 2, 3) }"/>
<xsl:param name="json-string" as="xs:string">
{
"foo" : "value 1",
"bar" : 3.14,
"baz" : true,
"items" : ["a", "b", "c" ]
}
</xsl:param>
<!-- a map constructed from a string containing JSON using the parse-json function https://www.w3.org/TR/xpath-functions/#func-parse-json -->
<xsl:param name="map2" as="map(*)" select="parse-json($json-string)"/>
<!-- a map constructed using the XSLT xsl:map and xsl:map-entry instructions https://www.w3.org/TR/xslt-30/#map-instructions -->
<xsl:param name="map3" as="map(*)">
<xsl:map>
<xsl:map-entry key="'key1'" select="'value 1'"/>
<xsl:map-entry key="'x'" select="3.1415927"/>
</xsl:map>
</xsl:param>
<!-- a map constructed by merging several maps using the map:merge function https://www.w3.org/TR/xpath-functions/#func-map-merge -->
<xsl:param name="map4" as="map(*)" select="map:merge(($map1, $map2, $map3))"/>
<!-- a map constructed by putting a new value into an existing map using the map:put function https://www.w3.org/TR/xpath-functions/#func-map-put -->
<xsl:param name="map5" as="map(*)" select="map:put($map1, 'new-key', 'new value')"/>
<xsl:template match="/">
<xsl:sequence select="$map1, $map2, $map3, $map4, $map5"/>
</xsl:template>
</xsl:stylesheet>
它的输出是(不幸的是,目前撒克逊人无法使用输出方法 'adaptive' 漂亮地 print/indent 项目):
map{"sequence":(1,2,3),"boolean":true(),"number":3.14,"string":"foo"}
map{"items":["a","b","c"],"foo":"value 1","bar":3.14e0,"baz":true()}
map{"key1":"value 1","x":3.1415927}
map{"items":["a","b","c"],"sequence":(1,2,3),"foo":"value 1","boolean":true(),"number":3.14,"string":"foo","key1":"value 1","bar":3.14e0,"x":3.1415927,"baz":true()}
map{"sequence":(1,2,3),"boolean":true(),"number":3.14,"string":"foo","new-key":"new value"}
显示一些构造数组的基本变体的类似示例是
<?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:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="xs math map array"
version="3.0">
<xsl:output method="adaptive" indent="yes"/>
<!-- array created with square array constructor https://www.w3.org/TR/xpath-31/#prod-xpath31-SquareArrayConstructor -->
<xsl:param name="array1" as="array(xs:integer)" select="[1, 2, 3, 4]"/>
<!-- array created with curly braces array constructor https://www.w3.org/TR/xpath-31/#prod-xpath31-CurlyArrayConstructor -->
<xsl:param name="array2" as="array(xs:string)" select="array{ (string-to-codepoints('A') to string-to-codepoints('E'))!codepoints-to-string(.) }"/>
<!-- if we use the square array constructor with an expression like above inside we get an array containing a sequence of strings -->
<xsl:param name="array3" as="array(xs:string*)" select="[ (string-to-codepoints('A') to string-to-codepoints('E'))!codepoints-to-string(.) ]"/>
<xsl:param name="json-array-as-string" as="xs:string">
[ { "foo" : 1 }, { "foo" : 2 }, { "foo" : 3 } ]
</xsl:param>
<!-- array constructed by parsing JSON input with function parse-json https://www.w3.org/TR/xpath-functions/#func-parse-json -->
<xsl:param name="array4" as="array(map(xs:string, xs:double))" select="parse-json($json-array-as-string)"/>
<!-- array constructed by joining two arrays using the function array:join https://www.w3.org/TR/xpath-functions/#func-array-join -->
<xsl:param name="array5" as="array(*)" select="array:join(($array1, $array2))"/>
<!-- array constructed by extracting subarray with function array:subarray https://www.w3.org/TR/xpath-functions/#func-array-subarray -->
<xsl:param name="array6" as="array(*)" select="array:subarray($array5, 3, 4)"/>
<xsl:template match="/">
<xsl:sequence select="$array1, $array2, $array3, $array4, $array5, $array6"/>
</xsl:template>
</xsl:stylesheet>
输出
[1,2,3,4]
["A","B","C","D","E"]
[("A","B","C","D","E")]
[map{"foo":1.0e0},map{"foo":2.0e0},map{"foo":3.0e0}]
[1,2,3,4,"A","B","C","D","E"]
[3,4,"A","B"]
http://xsltfiddle.liberty-development.net/eiQZDbd
在发布的这个阶段,可能还值得查看 XSLT 3 中的各种测试用例以及组合的 XPath 和 XQuery 测试套件,例如:
- https://dvcs.w3.org/hg/xslt30-test/file/tip/tests/strm/si-map 使用
xsl:map
和流 - https://dvcs.w3.org/hg/xslt30-test/file/tip/tests/fn/xml-to-json 有
xml-to-json
的测试
- https://dvcs.w3.org/hg/xslt30-test/file/tip/tests/fn/json-to-xml 有
json-to-xml
个测试用例。