XSLT 3 Saxon,使用深度更新和过滤器过滤不需要的数组元素

XSLT 3 Saxon, filtering unwanted array elements using deep-update and filter

XSLT 3 在使用 Saxon EE 库功能('saxon:with-pedigree'、'saxon:pedigree(.)?容器和 'deep-update')。下面的 XSLT 将具有 'visibility' 属性值的数组对象标识为 'false',然后从父数组对象中排除所选对象。跟踪显示预期值,但 Saxon Deep 更新操作逻辑失败。标识和数组过滤按预期工作,但将过滤后的数组分配给属性未按预期工作,感谢您的意见。

JSON嵌入在XML

<list><![CDATA[
{
"customers":[
    {
        "customerType": "householdCustomer",
        "firstName": "Adam",
        "lastName": "L",
        "orders": [
            {
                "type": "smallOrder",
                "refUri": "orders/smallorder/xyz",
                "total": 125.0,
                "shippingAddUri": "/customer/123/address/89ui",
                "messages": [
                    {
                        "visibility": true,
                        "description": " your ordered delivered",
                        "id": "2345"
                    },
                    {
                        "visibility": false,
                        "description": "supplier challenge - covid supply chain issues",
                        "id": "2167"
                    },
                    {
                        "visibility": false,
                        "description": "order routed to correct procurement",
                        "id": "2049"
                    },
                    {
                        "visibility": false,
                        "description": "order gone to wrong procurement center",
                        "id": "2047"
                    },
                    {
                        "visibility": true,
                        "description": "order initiated",
                        "id": "2045"
                    }
                ]
            },
            {
                "type": "smallOrder",
                "refUri": "orders/smallorder/567z",
                "total": 135.0,
                "shippingAddUri": "/customer/678/address/90ny",
                "messages": [
                    {
                        "id": "23456",
                        "visibility": true,
                        "description": " your ordered delayed"
                    },
                    {
                        "id": "21677",
                        "visibility": false,
                        "description": "internal costcenter labor strike "
                    },
                    {
                        "id": "20459",
                        "visibility": true,
                        "description": "order initiated"
                    }
                ]
            }
        ]
    },
    {
        "customerType": "householdCustomer",
        "firstName": "Thomas",
        "lastName": "N",
        "orders": [
            {
                "type": "smallOrder",
                "refUri": "orders/smallorder/xyz",
                "total": 125.0,
                "shippingAddUri": "/customer/123/address/89ui",
                "messages": [
                    {
                        "id": "2345",
                        "visibility": true,
                        "description": " your ordered delivered"
                    },
                    {
                        "id": "2167",
                        "visibility": false,
                        "description": "supplier challenge - covid supply chain issues"
                    },
                    {
                        "id": "2045",
                        "visibility": false,
                        "description": "order initiated"
                    }
                ]
            },
            {
                "type": "smallOrder",
                "refUri": "orders/smallorder/xr7z",
                "total": 234.0,
                "shippingAddUri": "/customer/uio/address/34bnmy",
                "messages": [
                    {
                        "id": "90",
                        "visibility": true,
                        "description": " your ordered delayed"
                    },
                    {
                        "id": "67",
                        "visibility": false,
                        "description": "Postal delays, finding alternative route "
                    },
                    {
                        "id": "34",
                        "visibility": true,
                        "description": "order initiated"
                    }
                ]
            }
        ]
    },
    {
        "customerType": "corporateCustomer",
        "corpName": "Telsoft Inc",
        "orders": [
            {},
            {}
        ]
    },
    {
        "customerType": "corporateCustomer",
        "corpName": "Orange Inc",
        "orders": [
            {},
            {}
        ]
    },
    {
        "customerType": "corporateCustomer",
        "corpName": "Notebook Inc",
        "orders": [
            {},
            {}
        ]
    }
]
}
]]>
</list>

XSLT 以本地方式转换 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:fn="http://www.w3.org/2005/xpath-functions" xmlns:saxon="http://saxon.sf.net/" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:err="http://www.w3.org/2005/xqt-errors" xmlns:f="http://example.com/f" extension-element-prefixes="saxon" exclude-result-prefixes="array fn map math xhtml xs err saxon" version="3.0">

    <xsl:output method="text" omit-xml-declaration="yes" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:template match="list" name="xsl:initial-template">
    
        <!-- read json from XML -->
        <xsl:variable name="data" as="map(*)"  select="parse-json(.)"/>
    
        <!-- identify household customers -->
        <xsl:variable name="householdCustomers" as="array(*)">
        <saxon:array    select="$data?customers?*[?customerType='householdCustomer']"/>
        </xsl:variable>
        
        
        <!-- produce hhsWithPedigree refrence structure using WithPedigree -->
        <xsl:variable name="hhsWithPedigree" as="array(*)">
        <saxon:array    select="$householdCustomers => saxon:with-pedigree()"/>
        </xsl:variable> 
        
        <!-- identify all objects with visibility as false' -->
        <xsl:variable name="visibilityArrayWithFalse" as="array(*)">
        <saxon:array    select="saxon:map-search($hhsWithPedigree, 'visibility', function($v){ fn:matches(
                    xs:string($v), 'false') })"/>
        </xsl:variable> 
        
        <!-- iterate through objects with 'visibility' attribute value as 'false' then identify root array
        and exclude the selected objects -->
        <xsl:for-each select="$visibilityArrayWithFalse?*?map">
            <xsl:variable name="visiOne" select="saxon:pedigree(.)?container"/>
            <saxon:deep-update
                 root = "$visiOne"
                select = "."
                action = " let  $filteredValues := array:filter(., function($v) {map:get($v,'visibility') eq true() }), $noOfValues := count($filteredValues), $trace := trace($filteredValues, 'I m tracing') return $filteredValues "/>
        </xsl:for-each>
        
                
        <xsl:value-of select=" $householdCustomers => serialize(map { 'method' : 'json', 'use-character-maps' : map { '/' : '/' } })"/>
    

    </xsl:template>

</xsl:stylesheet>

错误详细信息:

Error in saxon:deep-update/@root on line 31 column 222 of question-v1.xslt:
  SENR0001: Cannot serialize a map using this output method
     Focus
        Context item: map{"visibility":false(), "description":"supplier challenge - covid supply c...", "id":"2167", }
        Context position: 1
     Local variables
        $vv:v0 = coerced anon:f_1766145591
        $householdCustomers = [map{"firstName":"Adam", "lastName":"L", "customerType":"householdCustomer",  ...}, map{"firstName":"Thomas", "lastName":"N", "customerType":"householdCustomer",  ...}, ]
     invoked by unknown caller (class net.sf.saxon.expr.instruct.ForEach) at file:/C:/apps/xslt3/question-v1.xslt#26
  In template rule with match="list" on line 6 of question-v1.xslt
     Focus
        Context item: /list
        Context position: 1
     Local variables
        $vv:v0 = coerced anon:f_1766145591
        $householdCustomers = [map{"firstName":"Adam", "lastName":"L", "customerType":"householdCustomer",  ...}, map{"firstName":"Thomas", "lastName":"N", "customerType":"householdCustomer",  ...}, ]
     invoked by built-in template rule (text-only)
Cannot serialize a map using this output method

我认为部分错误是你使用了saxon:deep-update而没有将其结果存储在一个可以带XDM映射或数组的变量中,即指令returns/outputs这样的映射或数组在里面xsl:for-each 的输出方法为 text,您会收到错误消息,因为 saxon:deep-update 返回的结果序列化无法使用该方法 text 进行序列化。

我不太确定你想要实现什么,但我猜你不想输出 saxon:deep-update 的结果,你只希望它在你的地图上产生副作用。

阅读更多关于 saxon:deep-update 的内容,我想知道您是否需要所有明确的血统使用,以下

   <xsl:template match="list" name="xsl:initial-template">
        
        <!-- read json from XML -->
        <xsl:variable name="data" as="map(*)"  select="parse-json(.)"/>
        
        <!-- identify household customers -->
        <xsl:variable name="householdCustomers" select="array { $data?customers?*[?customerType='householdCustomer']}"/>


        <xsl:variable name="update-result" as="item()*">
            <saxon:deep-update root="$householdCustomers"
                select="?*?orders?*?messages"
                action="array:filter(., function($v) { $v?visibility })"/>
        </xsl:variable>     
        
        <xsl:value-of select=" $update-result => serialize(map { 'method' : 'json', 'indent' : true(), 'use-character-maps' : map { '/' : '/' } })"/>
        
      
</xsl:template>

产出

[
  {
    "lastName": "L",
    "orders": [
      {
        "total": 125,
        "messages": [
          { "visibility": true,"description": " your ordered delivered","id": "2345" },
          { "visibility": true,"description": "order initiated","id": "2045" }
        ],
        "shippingAddUri": "/customer/123/address/89ui",
        "refUri": "orders/smallorder/xyz",
        "type": "smallOrder"
      },
      {
        "total": 135,
        "messages": [
          { "visibility": true,"description": " your ordered delayed","id": "23456" },
          { "visibility": true,"description": "order initiated","id": "20459" }
        ],
        "shippingAddUri": "/customer/678/address/90ny",
        "refUri": "orders/smallorder/567z",
        "type": "smallOrder"
      }
    ],
    "customerType": "householdCustomer",
    "firstName": "Adam"
  },
  {
    "lastName": "N",
    "orders": [
      {
        "total": 125,
        "messages": [ { "visibility": true,"description": " your ordered delivered","id": "2345" } ],
        "shippingAddUri": "/customer/123/address/89ui",
        "refUri": "orders/smallorder/xyz",
        "type": "smallOrder"
      },
      {
        "total": 234,
        "messages": [
          { "visibility": true,"description": " your ordered delayed","id": "90" },
          { "visibility": true,"description": "order initiated","id": "34" }
        ],
        "shippingAddUri": "/customer/uio/address/34bnmy",
        "refUri": "orders/smallorder/xr7z",
        "type": "smallOrder"
      }
    ],
    "customerType": "householdCustomer",
    "firstName": "Thomas"
  }
]