Re: [xsl] inserting a child element while honoring the parent element's content model

Subject: Re: [xsl] inserting a child element while honoring the parent element's content model
From: "Chris Papademetrious christopher.papademetrious@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 20 Feb 2023 20:28:59 -0000
Hi Eliot,

I hadn't known about these operators, thank you!

I couldn't see a clean way to use "<<"  for a preceding-sibling-or-self:: axis
for this specific case, but I will definitely keep these operators in mind for
future DiTA processing tasks.


  *   Chris

From: Eliot Kimber eliot.kimber@xxxxxxxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Sent: Monday, February 20, 2023 11:19 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] inserting a child element while honoring the parent
element's content model

I don't know that it's a better solution, but I often use "milestone" nodes
and the "<<" and ">>" operators to position things:

<xsl:variable name="fromHere" as="element()" select="p[1]"/>
<xsl:variable name="beforeParaNodes" as="node()*" select="node()[. <<
$fromHere]"/>

I find this especially handy for getting nodes between two variable points,
like "all nodes before me that are preceding siblings or descendants of the
first child of my parent"-this is a challenge that comes up in DITA with some
frequency because of the rules around ID uniqueness within topics, for which
there's no easy single container.

Cheers,

E.
_____________________________________________
Eliot Kimber
Sr Staff Content Engineer
O: 512 554 9368
M: 512 554 9368
servicenow.com<https://urldefense.com/v3/__https:/www.servicenow.com__;!!A4F2
R9G_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb5Of_ppRPYZlMDTwBOyzMQZzj5RK
I1GKl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwcAQiMBy$>
LinkedIn<https://urldefense.com/v3/__https:/www.linkedin.com/company/servicen
ow__;!!A4F2R9G_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb5Of_ppRPYZlMDTwB
OyzMQZzj5RKI1GKl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwYIjkzB-$> |
Twitter<https://urldefense.com/v3/__https:/twitter.com/servicenow__;!!A4F2R9G
_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb5Of_ppRPYZlMDTwBOyzMQZzj5RKI1G
Kl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwaP9DBdK$> |
YouTube<https://urldefense.com/v3/__https:/www.youtube.com/user/servicenowinc
__;!!A4F2R9G_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb5Of_ppRPYZlMDTwBOy
zMQZzj5RKI1GKl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwQV7Vox1$> |
Facebook<https://urldefense.com/v3/__https:/www.facebook.com/servicenow__;!!A
4F2R9G_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb5Of_ppRPYZlMDTwBOyzMQZzj
5RKI1GKl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwaGwLyJN$>

From: Chris Papademetrious
christopher.papademetrious@xxxxxxxxxxxx<mailto:christopher.papademetrious@syn
opsys.com>
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx<mailto:xsl-list-service@xxxxxxxxxxxx
rytech.com>>
Date: Sunday, February 19, 2023 at 10:37 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx<mailto:xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
<xsl-list@xxxxxxxxxxxxxxxxxxxxxx<mailto:xsl-list@xxxxxxxxxxxxxxxxxxxxxx>>
Subject: [xsl] inserting a child element while honoring the parent element's
content model
[External Email]

________________________________
Hi everyone,

I needed to insert a child element while honoring the parent element's content
model. The solution took me some time to figure out, so I thought I'd share it
here.

Consider a <topic> element with the following content model:

topic = a?, b?, c?, j?, x?, y?, z?, topic*

Given the following input document with no <j> elements:

<?xml version="1.0" encoding="utf-8"?>
<topic>
  <!-- this is a comment -->
  <a/>
  <?my-a-pi?>
  <b/>
  <y/>

  <topic>
    <!-- y -->
    <y/>
  </topic>

  <topic>
    <!-- c -->
    <c/>
  </topic>

</topic>

I want to insert <j> into every <topic> element. To do this, I apply the
following general template that calls an "add-j" moded template on every
<topic> element lacking a <j>:

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="topic[not(j)]">
    <xsl:variable name="result" as="element()">
      <xsl:apply-templates select="." mode="add-j"/>
    </xsl:variable>
    <xsl:apply-templates select="$result"/>
  </xsl:template>

Then I define the "add-j" mode as follows:

  <!-- add <j> to <topic>, honoring the following content model:
         topic = a?, b?, c?, j, x?, y?, z?, topic* -->
 <xsl:template match="topic[not(j)]" mode="add-j">
    <xsl:variable name="stuff-before-j"
select="(a|b|c)/(.|preceding-sibling::node())" as="node()*"/>
    <xsl:copy>
      <xsl:sequence select="@*|$stuff-before-j"/>
      <j/>
      <xsl:sequence select="node() except $stuff-before-j"/>
    </xsl:copy>
  </xsl:template>

The tricky part was obtaining $stuff-before-j, since I wanted a
"preceding-or-self::" axis to retain any PIs or comments in their correct
place. Once I got that figured out, the rest fell into place.

The reason for a separate "add-j" moded template is that in my full
stylesheet, I have many templates doing things in many different places, and
so I use moded templates and <xsl:apply-templates/> so that everything plays
well together.

The solution works in either direction (stuff-before or stuff-after). In our
case, we are using DITA and the topics at the end of the content model can be
other specialized elements, so using the "stuff-before" flavor lets me match
any specialized topic that might follow.

I have much uglier implementations of content-model-aware insertion in past
stylesheets that I'll need to convert to this form.


  *   Chris

-----
Chris Papademetrious
Tech Writer, Implementation Group
(610) 628-9718 home office
(570) 460-6078 cell

XSL-List info and
archive<https://urldefense.com/v3/__http:/www.mulberrytech.com/xsl/xsl-list__
;!!A4F2R9G_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb5Of_ppRPYZlMDTwBOyzM
QZzj5RKI1GKl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwVbmP3eT$>
EasyUnsubscribe<https://urldefense.com/v3/__http:/lists.mulberrytech.com/unsu
b/xsl-list/3453418__;!!A4F2R9G_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb
5Of_ppRPYZlMDTwBOyzMQZzj5RKI1GKl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwfK610qD$>
(by email)
XSL-List info and
archive<https://urldefense.com/v3/__http:/www.mulberrytech.com/xsl/xsl-list__
;!!A4F2R9G_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb5Of_ppRPYZlMDTwBOyzM
QZzj5RKI1GKl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwVbmP3eT$>
EasyUnsubscribe<https://urldefense.com/v3/__http:/lists.mulberrytech.com/unsu
b/xsl-list/3380743__;!!A4F2R9G_pg!bkk70o5g-RGwSXrKgW2fH6Xv90mcrGbBq9QsgL6hjWb
5Of_ppRPYZlMDTwBOyzMQZzj5RKI1GKl2z9V4m4gBX6QalUkDUTHgvmskag-bCG8MwRJxbft9$>
(by email<>)

Current Thread