1

XSLT 3 is causing "SENR0001: Cannot serialize a map using this output method" error while transforming JSON natively using Saxon EE library capabilities ( 'saxon:with-pedigree' , 'saxon:pedigree(.)?container, and 'deep-update'). Below XSLT identifies array objects with 'visibility' attribute value as 'false' then excludes the selected objects from the parent array object. the trace is showing expected values but Saxon Deep update action logic is failing. Identification and array filtering are working as expected but assigning the filtered array to attribute is not working as expected, appreciate your input.

JSON Embedded in 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 to transform JSON natively.

<?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 Detail:

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
vcb
  • 13
  • 3

1 Answers1

0

I think part of the error is that you use the saxon:deep-update without storing its result in a variable that can take an XDM map or array, that instruction returns/outputs such a map or array inside of the xsl:for-each and with the output method being text you are getting the error because the serialization of the result returned by saxon:deep-update can't be serialized with that method text.

I am not quite sure what you want to achieve but I guess you don't want to output the result of saxon:deep-update, you just want its side effect on your map(s).

Reading up more on saxon:deep-update, I wonder whether you need all that explicit pedigree use, the following

   <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>

outputs

[
  {
    "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"
  }
]
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Thanks a ton, I am unnecessarily making the problem too complicated by using pedigree capability. The above solution looks less complicated, right on point. – vcb Jan 31 '22 at 23:56
  • 1
    Yes, the "pedigree" concept was my first attempt at providing this kind of capability as a low-level primitive, and deep-update was then created as a layer on top to try and make it more usable. It's still much more complex than I would like, and you should probably regard it as a work in progress. – Michael Kay Feb 01 '22 at 12:52