|
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: Sat, 25 Feb 2023 02:05:26 -0000 |
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() <=
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 |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| Re: [xsl] inserting a child element, Chris Papademetrious | Thread | Re: [xsl] inserting a child element, Chris Papademetrious |
| Re: [xsl] A beautiful way to popula, Dimitre Novatchev dn | Date | Re: [xsl] inserting a child element, Chris Papademetrious |
| Month |