xslt 3.0 和 xpath3.1 的数组和映射示例

Example of array and map for xslt 3.0 and xpath3.1

我想使用 XPath3.1 中的新功能,如 arraymap,这听起来像是一个可通过 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>

所以有一个简单有效的代码可以证明 arraymap 的强大功能吗?谢谢!

地图主要可以帮助解决两个问题:

  1. 流式传输,参见 https://www.w3.org/TR/xslt-30/#maps-streaming,尽管在使用 Saxon 9.8 HE 时您不能使用流式传输。
  2. 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 测试套件,例如: