Subject: Re: [xsl] Better "Report Map" Function? From: "Eliot Kimber ekimber@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Sat, 6 Oct 2018 15:24:26 -0000 |
Now that I look at my code again I think the lack of return type was in intentional in that I was trying to have both the overall map data shown as well as get the Saxon element serialization when outside of a "value-of" context. But now I realize that the way I've used it is usually in "{local:report-map($map)}", which of course undoes that. Hmph. But setting the return type to xs:string without doing more with element() values would be bad. Cheers, E. -- Eliot Kimber http://contrext.com o;?On 10/6/18, 10:10 AM, "Eliot Kimber ekimber@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote: You're right, I failed to set a return type (which I would normally always do). The intent is definitely to return a string. I haven't tried to make it 100% general at this point since this was something I hacked quickly in the context of debugging other code. I will correct the key sorting--I knew assuming the keys were strings was not sufficient but all the maps in my current projects only use string keys. For handling the possible entry values, I was pretty much just adding handlers as I needed them. For example, using this on the result of Saxon's collection() extensions that return maps of file information made it clear that I needed an "other" category... Cheers, Eliot -- Eliot Kimber http://contrext.com o;?On 10/6/18, 9:49 AM, "Michael Kay mike@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote: I wonder if this is really what you want? You haven't declared a return type for the function, so there's going to be no conversion applied, which means it's going to output a sequence of interspersed text and element nodes. That's probably fine if the function call always appears within xsl:value-of, but it's not very convenient if, for example, you want to call it as an argument of contains() or substring(). I would have thought a function that returned a string would be more useful. And a function that only handles map values that are maps, elements, document nodes, single strings, single booleans, or single integers doesn't feel very general-purpose. But you're right that there's probably nothing off-the-shelf that gives you exactly what you want. For many purposes (e.g. diagnostic output) the serialize() function with method=adaptive will be adequate, but if you want something better then you have to do it yourself. Incidentally, sorting the keys of a map like this will fail if the keys include non-ordered values such as QNames, of if they include a mixture of strings and numbers. If you want to be sure the sort won't fail, convert keys to strings before sorting. Michael Kay Saxonica > On 6 Oct 2018, at 14:33, Eliot Kimber ekimber@xxxxxxxxxxxx <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote: > > I needed a way to report the contents of maps as nicely-formatted strings using XSLT 3 and Saxon (Saxon's built-in serialization of maps did not really satisfy me). > > Here's my solution: > > <xsl:function name="local:report-map"> > <xsl:param name="map" as="map(*)"/> > <xsl:param name="level" as="xs:integer"/> > > <xsl:variable name="indent" as="xs:string?" > select="(for $i in 1 to $level return ' ') => string-join()" > /> > <xsl:text>
{$indent}{{</xsl:text> > <xsl:for-each select="map:keys($map) => sort()"> > <xsl:variable name="key" select="."/> > <xsl:variable name="value" select="map:get($map, $key)"/> > <xsl:text>
{$indent} "{$key}" : </xsl:text> > <xsl:choose> > <xsl:when test="$value instance of map(*)"> > <xsl:text> Map:</xsl:text> > <xsl:sequence select="local:report-map($value, $level + 3)"/> > </xsl:when> > <xsl:when test="$value instance of element()"> > <xsl:sequence select="$value"/> > </xsl:when> > <xsl:when test="$value instance of document-node()"> > <xsl:text> document-node(): {name($value/*)} - "{document-uri($value)}"</xsl:text> > </xsl:when> > <xsl:when test="$value instance of xs:string or $value instance of xs:boolean or $value instance of xs:integer"> > <xsl:text>"{$value}"</xsl:text> > </xsl:when> > <xsl:otherwise> > <xsl:text>unhandled value</xsl:text> > </xsl:otherwise> > </xsl:choose> > </xsl:for-each> > <xsl:text>
{$indent}}}</xsl:text> > </xsl:function> > > Which produces output like this: > > { > "baseType" : "map" > "doc" : document-node(): map - "file:/Users/ekimber/workspace/paccar/repo/paccar/sample_data/test-project/ca libration-data/MX11_NA/calibrationSLMP_MX11_NA.ditamap" > "engineFamilies" : "10.8M01" > "key" : "" > "relpath" : "calibration-data/MX11_NA/calibrationSLMP_MX11_NA.ditamap" > "type" : "map" > } > > I'm happy with the result but wondering if there's not a more efficient/cleaner/more elegant way to do the same thing? > > Cheers, > > E. > -- > Eliot Kimber > http://contrext.com
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Better "Report Map" Funct, Eliot Kimber ekimber | Thread | Controlling Debugging Messages (was, Eliot Kimber ekimber |
Re: [xsl] Better "Report Map" Funct, Eliot Kimber ekimber | Date | [xsl] another beginner question - s, Dave Lang emaildavel |
Month |