xsl-list
[Top] [All Lists]

Re: [xsl] constructing arrays in XSLT with templates

2021-06-19 05:30:21
That looks very good.

I'm able to get your recommendation to work:

<books>
  <book>
    <title>The C Programming Language</title>
    <author>Brian Kernighan</author>
    <author>Dennis Ritchie</author>
  </book>
  <book out-of-print="true">
    <title>Principles of Compiler Design</title>
    <author>Alfred V. Aho</author>
    <author>Jeffrey D. Ullman</author>
    <author>J. E. Hopcrof</author>
  </book>
</books>

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:map="http://www.w3.org/2005/xpath-functions/map";
  version="3.0">

  <xsl:output method="json" indent="yes" />

  <xsl:template match="/" >
    <xsl:sequence select="
    map {
      'books' : array {
        books/book ! map:merge((
          map:entry('title',        title         !string()   ),
          map:entry('authors',      array { author!string() } ),
          @out-of-print[. eq 'true'] !
          map:entry('out-of-print', true())
        ))
      }
    }" />
  </xsl:template>

</xsl:stylesheet>

But I was hoping for something closer to this:

    map {
      'books' : array {
        books/book ! map:merge((
          map:entry('title',        title         !string()   ),
          map:entry('authors',      array { author!string() } ),
*          map:entry('out-of-print', true())[current()/@out-of-print eq
'true']*
        ))
      }
    }

This latter one doesn't seem to work, at least not within Saxon-JS (via
your excellent *xslt3fiddle* of which I am an ardent user).

I'm curious why the latter doesn't work but I suspect that the context is
not what I'm thinking that it is within that predicate.

In any case, your generous help has been quite an eye-opener for me and has
steered me in a much more expressive xpath direction.

Thanks very much

-alan

On Sat, Jun 19, 2021 at 11:25 AM Martin Honnen 
martin(_dot_)honnen(_at_)gmx(_dot_)de <
xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:


Am 19.06.2021 um 10:54 schrieb Alan Painter 
alan(_dot_)painter(_at_)gmail(_dot_)com:
But I'm wondering what the equivalent would be for conditional map
entries.


Supposing that there is an additional optional attribute on the 'book'
element of the original xml, 'out-of-print="true"'.
Furthermore, let's say that the JSON maps in the 'books' array contain
an additional field when a book is out of print.

In XSLT map entries, you can write:

<xsl:map>
      <xsl:map-entry key="'title'"   select="title!string()"
    />
      <xsl:map-entry key="'authors'" select="array { ./author!string()
}" />

      <xsl:if test="@out-of-print and @out-of-print eq 'true'" >
          <xsl:map-entry key="'out-of-print'" select="true()" />
      </xsl:if>
</xsl:map>

But I'm thinking that there is not a way to express this with the 'map
{ ... }' form in xpath.

map {
    'title'        : title!string(),
    'authors'      : array { author/string() },
  ( 'out-of-print' : true() )[@out-of-print and @out-of-print eq 'true']
}

Is there any way of doing something like this using in-line xpath?


My first instinct would be that the data is more consistent if you just do


   <xsl:template match="/">
     <xsl:sequence
       select="map {
                'books' : array {
                   books/book ! map {
                     'title' : title!string(),
                     'authors' : array { author/string() },
                     'out-of-print' : @out-of-print = 'true'
                   }
                 }
               }"/>
   </xsl:template>


i.e. give any map representing a book a property of the name
out-of-print with the right value.


Otherwise I think you can use map:merge


   <xsl:template match="/">
     <xsl:sequence
       select="map {
                'books' : array {
                   books/book !
                     map:merge((
                       map {
                         'title' : title!string(),
                         'authors' : array { author/string() }
                       },
                       @out-of-print ! map:entry(local-name(), boolean(.)))
                     )
                   }
               }"/>
   </xsl:template>


with xmlns:map="http://www.w3.org/2005/xpath-functions/map";




--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--
<Prev in Thread] Current Thread [Next in Thread>