I am trying to write some xslt that will enumerate all images in my xml(s!)
i am using a key for this so that i can reference the images later in the content, my problem here is i cant figure out how to get a consistent value. Meaning: the xml has references to multiple other documents which i am loading using document(), whenever i "enter" a new document the key is reset, so in documents that have 2 images i get a count of two, in others one
so you can imagine
root doc:
<root>
<chapter href="chapters/doc1.xml"/>
<chapter href="chapters/doc2.xml"/>
</root>
doc1.xml
<root>
<image id="a"/>
<image id="b"/>
</root>
doc2.xml
<root>
<image id="f"/>
</root>
i found a old thread here on stackoverflow that i think goes kind of in my direction: XSLT: create 'key' across multiple documents? but i was not able to make it work.
what is currently working: i have defined a key
<xsl:key name="image" match="image" use="@id"/>
that im using later like this
key value for image:<xsl:value-of select="count(key('image', @id)/preceding::image) + 1"/>
this always produces the mentioned result (for doc1 i get "key value for image:1 key value for image:2
" bur for doc2 i get "key value for image:1
" again and here i would expect a 3)
trying to adapt to the linked post i have tried to load all documents using collection and at create a new key hoping it would yield me at least all images for the start
<xsl:key name="images" match="image" use="all"/>
<xsl:variable name="location"><xsl:value-of select="$xml-base"/>/chapters?select=*.xml;recurse=yes</xsl:variable>
<xsl:variable name="documents">
<xsl:value-of select="collection($location)"/>
</xsl:variable>
<xsl:for-each select="collection($location)">
<xsl:message>
<xsl:value-of select="./count(key('figure','all'))"/>
</xsl:message>
</xsl:for-each>
and that always gives me 0 i am not even sure if using key is the right approach here
tldr: how can i enumerate images in xslt across multiple documents?
*edit as i think it was a bit unclear: i have multiple xml inputs imported by a root xml, all of them can contain images i have a final output file that needs to enumerate all images continiously and be able to reference them
That last document has a single image
element, therefore that image
doesn't have any preceding::image
.
It is also not clear why you need a key at all if you want to count image
elements, count(//image)
for a single document or count(document(/root/chapter/@href)//image)
for using the document
function on that first sample or count(collection('chapters?select=*.xml;recurse=yes')//image)
for the XSLT 2/3 and Saxon 9 specific collection()
call should do.
<xsl:key name="images" match="image" use="all"/>
is meaningless unless any image
element has child elements named all
.
Dealing with severals documents is possible but requires some extra effort. If you need general processing and can't push all elements together through a template to exploit position()
but somehow need to index all those image
elements then perhaps doing <xsl:variable name="images" select="document(/root/chapter/@href)//image"/>
and <xsl:variable name="image-ids" select="for $img in $images return generate-id($img)"/>
and then simply using <xsl:value-of select="index-of($image-ids, generate-id())"/>
in any xsl:template match="image"
should work.
The for $img in $images return generate-id($img)
can be written more compactly in XSLT 3 as $images ! generate-id()
.