[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: inserting a child element while honoring the paren

Subject: Re: inserting a child element while honoring the parent element's content model
From: "Chris Papademetrious christopher.papademetrious@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 25 Feb 2023 02:05:26 -0000
Re:  inserting a child element while honoring the paren
Hi everyone,

Here is a template to perform content-model-aware element insertion (more to
come):


  <!-- perform content-aware insertion on an element -->
  <xsl:template match="*" mode="insert-stuff">
    <xsl:param name="path" as="xs:string*"/>
    <xsl:param name="content" as="element()*" tunnel="yes"/>

    <!-- if path levels remain to recurse, get the next path level -->
    <xsl:variable name="path-element-name" select="head($path)"
as="xs:string?"/>
    <xsl:variable name="path-element-original" select="*[name() eq
$path-element-name]" as="element()?"/>

    <!-- choose what to insert in this current element (the "parent") -->
    <xsl:variable name="parent-name" select="name()" as="xs:string"/>
    <xsl:variable name="insert-in-parent" as="node()*">
      <xsl:choose>
        <xsl:when test="$path-element-name">
          <!-- we are still recursing the path - create or modify the next
path element -->
          <xsl:variable name="path-element-to-process" as="element()">
            <xsl:choose>
              <xsl:when test="$path-element-original">
                <!-- the path element exists at this level; use it -->
                <xsl:sequence select="$path-element-original"/>
              </xsl:when>
              <xsl:otherwise>
                <!-- the path element does not exist at this level; create it
-->
                <xsl:element name="{$path-element-name}"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:variable>
          <!-- recursively process this path element, then insert it into its
parent below -->
          <xsl:apply-templates select="$path-element-to-process"
mode="#current">
            <xsl:with-param name="path" select="tail($path)"
as="xs:string*"/>
          </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise>
          <!-- we've reached the end of the path - insert the content at this
level -->
          <xsl:sequence select="$content"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <!-- get the content model we must respect in this current element (the
"parent") -->
    <xsl:if test="empty($content-models($parent-name))">
      <xsl:message terminate="yes" expand-text="yes">No content model found
for '{$parent-name}'.</xsl:message>
    </xsl:if>
    <xsl:variable name="content-model" select="$content-models($parent-name)"
as="xs:string+"/>

    <!--iteratively insert one element at a time into the parent -->
    <xsl:iterate select="$insert-in-parent">
      <xsl:param name="current-parent" select="." as="element()"/>
      <xsl:on-completion select="$current-parent"/>
      <xsl:variable name="this-element-to-insert" select="." as="element()"/>

      <!-- compute an updated parent element with this content element
inserted -->
      <xsl:variable name="new-parent" as="element()">
        <!-- get all content up to (and including) the current insertion
element type, per the content model -->
        <xsl:variable name="this-element-name"
select="name($this-element-to-insert)" as="xs:string"/>
        <xsl:if test="empty(index-of($content-model, $this-element-name))">
          <xsl:message terminate="yes"
expand-text="yes">'{$this-element-name}' not found in content model for
'{$parent-name}'.</xsl:message>
        </xsl:if>
        <xsl:variable name="preceding-elements"
select="$current-parent/*[name() = $content-model[position() &lt;=
index-of($content-model, $this-element-name)]]" as="element()*"/>
        <xsl:variable name="preceding-nodes"
select="$preceding-elements/(.|preceding-sibling::node())" as="node()*"/>
        <!-- create the updated parent element -->
        <xsl:copy select="$current-parent">
          <!-- include the preceding content (if we updated an existing path
element, don't include the original) -->
          <xsl:sequence select="@*, $preceding-nodes except
$path-element-original"/>
          <!-- insert this element -->
          <xsl:sequence select="$this-element-to-insert"/>
          <!-- include the following content -->
          <xsl:sequence select="node() except ($preceding-nodes)"/>
        </xsl:copy>
      </xsl:variable>
      <xsl:next-iteration>
        <xsl:with-param name="current-parent" select="$new-parent"/>
      </xsl:next-iteration>
    </xsl:iterate>
  </xsl:template>

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.