xmlxsltdita

Inserting a new DITA body element


Looking to transform an XML file to a valid DTD topic. To do this I need to insert a body element as shown.

<topic>
<title>My Title</title>
==><body>
<para>Intro text goes here.</para>
  <section/>
  <section/>
==></body>
</topic>

Solution

  • If you need to add a body element as a child of topic, add a template that matches topic and add the element there.

    The only slightly tricky part is that you want the title outside of body, so you'll have to separate that from the rest of the children.

    Here's an XSLT 3.0 example. (I also added an id attribute to topic and changed para to p so it would be valid.)

    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output indent="yes" doctype-public="-//OASIS//DTD DITA Topic//EN" doctype-system="topic.dtd"/>
        <xsl:strip-space elements="*"/>
        
        <xsl:mode on-no-match="shallow-copy"/>
        
        <xsl:template match="topic">
            <topic id="{generate-id()}">
                <xsl:apply-templates select="@*|title"/>
                <body>
                    <xsl:apply-templates select="node() except title"/>
                </body>
            </topic>
        </xsl:template>
        
        <xsl:template match="para">
            <p>
                <xsl:apply-templates select="@*|node()"/>
            </p>
        </xsl:template>
        
    </xsl:stylesheet>
    

    If you can't use XSLT 3.0, here's a 1.0 version (without xsl:mode and except)...

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output indent="yes" doctype-public="-//OASIS//DTD DITA Topic//EN" doctype-system="topic.dtd"/>
        <xsl:strip-space elements="*"/>
        
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
        
        <xsl:template match="topic">
            <topic id="{generate-id()}">
                <xsl:apply-templates select="@*|title"/>
                <body>
                    <xsl:apply-templates select="node()[not(self::title)]"/>
                </body>
            </topic>
        </xsl:template>
        
        <xsl:template match="para">
            <p>
                <xsl:apply-templates select="@*|node()"/>
            </p>
        </xsl:template>
        
    </xsl:stylesheet>
    

    Fiddle: http://xsltfiddle.liberty-development.net/3Nzb5iZ