Converting attributes set in the map to element in a prolog

Post here questions and problems related to editing and publishing DITA content.
gbv34
Posts: 105
Joined: Thu Jan 20, 2022 12:36 pm

Converting attributes set in the map to element in a prolog

Post by gbv34 »

Hello everyone!
This is a task I'm currently struggling with.
I work with people who'd like to leverage the subject scheme map and its controlled values to automatically convert the attributes initially declared o the topicrefs as elements in topics' prolog.
Basically, my plugin relies on the following extension point <feature extension="dita.xsl.mappull" file="./xsl/backup-subjectschememap-attributes-2-elements.xsl"/>. What I do in it is creating a corresponding "othermeta" elements for each attribute from this list: "audience," "status," "props," "otherprops," "rev," "product," and "platform."

For now , I have this XSLT:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:dita-ot="http://dita-ot.sourceforge.net/ns/201007/dita-ot"
    xmlns:mappull="http://dita-ot.sourceforge.net/ns/200704/mappull"
    xmlns:ditamsg="http://dita-ot.sourceforge.net/ns/200704/ditamsg"
    xmlns:saxon="http://saxon.sf.net/"
    exclude-result-prefixes="xs dita-ot mappull ditamsg saxon">

    
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="*[contains(@class, ' map/topicref ')]">  
      <xsl:call-template name="processTopicref">
        <xsl:with-param name="element" select="."/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template name="processTopicref">
        <xsl:param name="element"/>
        <xsl:message>XSLT transform started!</xsl:message>   
        <xsl:variable name="xtrf" select="$element/@xtrf"/>
        <xsl:variable name="attributes"
            select="tokenize($element/@*[local-name() = ('audience', 'status', 'props', 'otherprops', 'rev', 'product', 'platform')], ' ')"/>

        <xsl:copy>
            <xsl:apply-templates
                select="$element/@*[not(local-name() = ('audience', 'status', 'props', 'otherprops', 'rev', 'product', 'platform'))]"/>
            <xsl:apply-templates select="$element/node()"/>
            <topicmeta class="- map/topicmeta ">
                <xsl:copy-of select="topicmeta/*[not(self::othermeta)]"/>
                <xsl:if test="@audience">
                    <xsl:variable name="attributes"
                        select="tokenize($element/@*[local-name() = ('audience')], ' ')"/>
                    <xsl:for-each select="$attributes">
                        <xsl:variable name="attrValue" select="."/>
                        <othermeta name="audience" content="{$attrValue}" xtrf="{$xtrf}"
                            class="- topic/othermeta "/>
                    </xsl:for-each>
                </xsl:if>
            </topicmeta>

        </xsl:copy>
    </xsl:template>
  
</xsl:stylesheet>
I see the temporary source for the map correctly populates the othermeta in the topicref, but I don't retrieve navtitle or the other elements that should be included in it too. I wonder how I could call the remaining processing to be applied.

I have tried using the topicpull extension point, navtitle and linktext are provided, but I loose my transformation for the othermeta element creation.
I feel stuck at this point and any suggestion would be helpful.
Thanks a lot for your attention :)
------
Gaspard
chrispitude
Posts: 907
Joined: Thu May 02, 2019 2:32 pm

Re: Converting attributes set in the map to element in a prolog

Post by chrispitude »

Hi Gaspard,

When I want to "wedge into" existing processing to apply some incremental change to it, I use a two-step approach.

First, I capture the results of <xsl:next-match>, which returns the result of whatever processing would have applied if the current template did not exist, then apply my own moded template to it:

Code: Select all

  <!-- call original processing, then call moded template to post-process results -->
  <xsl:template match="*[contains(@class, ' map/topicref ')]">  
    <xsl:variable name="original" as="element()" select="."/>
    <xsl:variable name="result" as="element()?">
      <xsl:next-match/>  <!-- apply default processing first -->
    </xsl:variable>
    <xsl:apply-templates select="$result" mode="add-stuff">
      <xsl:with-param name="original" as="element()" select="$original" tunnel="yes"/>
    </xsl:apply-templates>
  </xsl:template>
Second, I define the moded templates that do the actual post-processing:

Code: Select all

  <!-- moded template post-processing -->
  <xsl:mode name="add-stuff" on-no-match="shallow-copy"/>
  <xsl:template match="*[contains(@class, ' map/topicref ')]" mode="add-stuff">
    <xsl:param name="original" as="element()" required="yes" tunnel="yes"/>
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" mode="#current"/>
    </xsl:copy>
  </xsl:template>
The <xsl:mode on-no-match="shallow-copy"/> declaration is the XSLT3 way to define an identity transform. Note that I pass the original (pre-<xsl:next-match/>) element to the post-processing templates so that they have access to all the data in the original element.

One key advantage of this approach is that you can apply your post-processing anywhere in the element or attribute hierarchy. Just define a moded template that applies to the thing you want to post-process. All the other stuff will just be copied as-is due to the identity template.

The example above does not actually change any content, but you can add whatever post-processing you need in moded templates. Don't forget to change your XSLT version to 3 if needed!
Radu
Posts: 9059
Joined: Fri Jul 09, 2004 5:18 pm

Re: Converting attributes set in the map to element in a prolog

Post by Radu »

Chris, thanks for replying to this one, I saw the post at some point but somehow did not receive an email notification for it or it got deleted.
Gaspard, in general for such problems which are not related to Oxygen's functionality you can also try to start a DITA OT discussion:
https://github.com/orgs/dita-ot/discussions
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
gbv34
Posts: 105
Joined: Thu Jan 20, 2022 12:36 pm

Re: Converting attributes set in the map to element in a prolog

Post by gbv34 »

Thank you, to both of you,
I will explore the solution Chris proposed and will moved to the OT group, because my hunch tells me I'm not done with this issue yet :)
------
Gaspard
Post Reply