Using XSLT to create DITA to XML output multiple same element comes under child element to a parent element

423 views Asked by At

While I'm converting input DITA file to XML output, multiple same elements like <p class="- topic/p " outputclass="MLU_Intro"> to single parent tag are converted into multiple same tag.

I'm new to XSLT, Please anyone guide me to resolve above issue.

My input XML file is:

<!DOCTYPE topic PUBLIC "urn:pubid:com.staywell.doctypes:doctypes:dita:topic" "topic.dtd">
<topic xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" xmlns:r="http://www.rsuitecms.com/rsuite/ns/metadata" class="- topic/topic " ditaarch:DITAArchVersion="1.2" domains="(topic hi-d) (topic indexing-d)(topic d4p_formatting-d)a(props d4p_renditionTarget)(topic d4p_math-d)(topic d4p_variables-d)(topic d4p_verse-d)(topic learningInteractionBase2-d learning2-d+learning-d)(topic learningBase+learningInteractionBase-d)(topic learningInteractionBase-d)(topic learningInteractionBase2-d)(topic xml-d)a(base rsuiteIdAtt)(topic sdClassification-d)  " id="d43e3" outputclass="DOCTYPE-MLU" r:rsuiteId="6514" xml:lang="en-US">
  <title class="- topic/title " outputclass="MLU">All About the A1C</title>
  <body class="- topic/body ">
    <p class="- topic/p " outputclass="MLU_Code">TP_02A</p>
    <p class="- topic/p " outputclass="MLU_Type">Horizontal Click &amp; Learn</p>
  </body>
  <topic class="- topic/topic " ditaarch:DITAArchVersion="1.2" domains="(topic hi-d) (topic indexing-d)(topic d4p_formatting-d)a(props d4p_renditionTarget)(topic d4p_math-d)(topic d4p_variables-d)(topic d4p_verse-d)(topic learningInteractionBase2-d learning2-d+learning-d)(topic learningBase+learningInteractionBase-d)(topic learningInteractionBase-d)(topic learningInteractionBase2-d)(topic xml-d)a(base rsuiteIdAtt)(topic sdClassification-d)  " id="d43e15" outputclass="TOPIC-MLU-Header" r:rsuiteId="6515" xml:lang="en-US">
    <title class="- topic/title " outputclass="MLU-Header">Header</title>
    <body class="- topic/body ">
      <p class="- topic/p " outputclass="MLU_Category">Management</p>
      <p class="- topic/p " outputclass="MLU_Banner_Display">Yes</p>
      **
      <p class="- topic/p " outputclass="MLU_Intro">It’s great that.</p>
      <p class="- topic/p " outputclass="MLU_Intro">
        <ph class="- topic/ph " outputclass="Bold">Why the A1C</ph>
      </p>
      <p class="- topic/p " outputclass="MLU_Intro">An A1C test.</p>
      <p class="- topic/p " outputclass="MLU_Intro">
        <ph class="- topic/ph " outputclass="Bold">What to</ph>
        <ph class="- topic/ph " outputclass="Bold">Results</ph>
      </p>
      <p class="- topic/p " outputclass="MLU_Intro">An A1C test result.</p>
      **
      <p class="- topic/p " outputclass="MLU_Directions">CLICK ON EACH ICON TO LEARN MORE.</p>
    </body>
  </topic>
</topic>

XSL which I have used:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" encoding="UTF-8" doctype-system="../DTDs/MLU.dtd" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="topic[@outputclass = 'DOCTYPE-MLU']">
    <MLU>
      <clickLearnHorizontal>
        <xsl:apply-templates />
      </clickLearnHorizontal>
    </MLU>
  </xsl:template>

  <xsl:template match="topic[@outputclass = 'TOPIC-MLU-Header']">
    <header>
      <trackingSettings>
        <urlcode>
          <xsl:value-of select="//p[@outputclass = 'MLU_Code']" />
        </urlcode>
        <apiurl>http://mlucenter.com/like/api</apiurl>
      </trackingSettings>
      <page>
        <xsl:value-of select="text()" />
      </page>
      <banner>
        <enabled>true</enabled>
        <text>
          <xsl:value-of select="//title[@outputclass = 'MLU']" />
        </text>
      </banner>
      <xsl:apply-templates />
    </header>
  </xsl:template>

  <xsl:template match="body">
    <xsl:apply-templates />
  </xsl:template>

  <xsl:template match="p[@outputclass = 'MLU_Code']" />
  <xsl:template match="title[@outputclass = 'MLU']" />
  <xsl:template match="title[@outputclass = 'MLU-Header']" />
  <xsl:template match="p[@outputclass = 'MLU_Condition']" />
  <xsl:template match="p[@outputclass = 'MLU_Type']" />
  <xsl:template match="p[@outputclass = 'MLU_Category']" />
  <xsl:template match="p[@outputclass = 'MLU_Banner_Display']" />
  <xsl:template match="p[@outputclass = 'MLU_Banner_Color']" />

  <xsl:template match="p">
    <introText>
      <text>
        <xsl:for-each select="p[@outputclass = 'MLU_Intro']">
          <p>
            <xsl:apply-templates />
          </p>
        </xsl:for-each>
      </text>
    </introText>
  </xsl:template>

  <!--<xsl:template match="p[@outputclass = 'MLU_Intro']"> </xsl:template>-->

  <xsl:template match="p[@outputclass = 'MLU_Directions']">
    <directionText>
      <text>
        <xsl:value-of select="//p[@outputclass = 'MLU_Directions']" />
      </text>
    </directionText>
  </xsl:template>

  <xsl:template match="title[@outputclass = 'MLU-Body']" />
  <xsl:template match="title" />
  <xsl:template match="ph">
    <xsl:apply-templates />
  </xsl:template>

  <xsl:template match="p[@outputclass = 'MLU_Item_Button']" />
  <xsl:template match="p[@outputclass = 'MLU_Item_Title_Position']" />
  <xsl:template match="bodydiv[@outputclass = 'Item_Defaults']" />

  <xsl:template match="bodydiv">
    <xsl:apply-templates />
  </xsl:template>

  <xsl:template match="p">
    <p>
      <xsl:apply-templates />
    </p>
  </xsl:template>

  <!--
  <xsl:template match="p[@outputclass = 'MLU_Intro']">
    <p>
    <xsl:apply-templates/>
    </p>
  </xsl:template>
  -->

  <xsl:template match="image" />
  <xsl:template match="@MLU_Banner_Display" />
  <xsl:template match="@class">
    <!--<xsl:apply-templates/>-->
  </xsl:template>

  <xsl:template match="ul">
    <ul>
      <xsl:apply-templates />
    </ul>
  </xsl:template>

  <xsl:template match="ol">
    <ol>
      <xsl:apply-templates />
    </ol>
  </xsl:template>

  <xsl:template match="li">
    <li>
      <xsl:apply-templates />
    </li>
  </xsl:template>

  <xsl:template match="ph[@outputclass = 'Bold']">
    <strong>
      <xsl:apply-templates />
    </strong>
  </xsl:template>
</xsl:stylesheet>

Output XML which I got as:

<!DOCTYPE MLU
  SYSTEM "../DTDs/MLU.dtd">
<MLU>
  <clickLearnHorizontal>
    <header>
      <trackingSettings>
        <urlcode>TP_02A</urlcode>
        <apiurl>http://mlucenter.com/like/api</apiurl>
      </trackingSettings>
      <page />
      <banner>
        <enabled>true</enabled>
        <text>All About the A1C</text>
      </banner>
      **
      <p>It’s great.</p>
      <p>
        <strong>Why the A1C</strong>
      </p>
      <p>An A1C test.</p>
      <p>
        <strong>What to Expect</strong>
        <strong>Results</strong>
      </p>
      <p>An A1C test.</p>
      **
      <directionText>
        <text>CLICK ON EACH ICON TO LEARN MORE.</text>
      </directionText>
    </header>
  </clickLearnHorizontal>
</MLU>

But I expected output as:

<MLU>
  <clickLearnHorizontal>
    <header>
      <trackingSettings>
        <urlcode>TP_02A</urlcode>
        <apiurl>http://mlucenter.com/like/api</apiurl>
      </trackingSettings>
      <page />
      <banner>
        <enabled>true</enabled>
        <text>All About the A1C</text>
      </banner>
      **
      <introText>
        <text>
          <p>It’s great.</p>
          <p>
            <strong>Why the A1C</strong>
          </p>
          <p>An A1C test.</p>
          <p>
            <strong>What to Expect</strong>
            <strong>Results</strong>
          </p>
          <p>An A1C test.</p>
        </text>
      </introText>
      **
      <directionText>
        <text>CLICK ON EACH ICON TO LEARN MORE.</text>
      </directionText>
    </header>
  </clickLearnHorizontal>
</MLU>
2

There are 2 answers

2
Martin Honnen On BEST ANSWER

You can use for-each-group group-adjacent as follows:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" doctype-system="../DTDs/MLU.dtd" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="topic[@outputclass = 'DOCTYPE-MLU']">
        <MLU>
            <clickLearnHorizontal>
                <xsl:apply-templates/>
            </clickLearnHorizontal>
        </MLU>
    </xsl:template>
    <xsl:template match="topic[@outputclass = 'TOPIC-MLU-Header']">
        <header>
            <trackingSettings>
                <urlcode>
                    <xsl:value-of select="//p[@outputclass = 'MLU_Code']"/>
                </urlcode>
                <apiurl>http://mlucenter.com/like/api</apiurl>
            </trackingSettings>
            <page><xsl:value-of select="text()" /></page>
            <banner>
                <enabled>true</enabled>
                <text>
                    <xsl:value-of select="//title[@outputclass = 'MLU']"/>
                </text>
            </banner>
            <xsl:apply-templates/>
        </header>
    </xsl:template>
    <xsl:template match="body">
        <xsl:for-each-group select="*" group-adjacent="boolean(self::p[@outputclass = 'MLU_Intro'])">
            <xsl:choose>
                <xsl:when test="current-grouping-key()">
                    <introText>
                        <text>
                            <xsl:apply-templates select="current-group()"/>
                        </text>
                    </introText>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>
    <xsl:template match="p[@outputclass = 'MLU_Code']"> </xsl:template>
    <xsl:template match="title[@outputclass = 'MLU']"> </xsl:template>
    <xsl:template match="title[@outputclass = 'MLU-Header']"> </xsl:template>
    <xsl:template match="p[@outputclass = 'MLU_Condition']"> </xsl:template>
    <xsl:template match="p[@outputclass = 'MLU_Type']"> </xsl:template>
    <xsl:template match="p[@outputclass = 'MLU_Category']"> </xsl:template>
    <xsl:template match="p[@outputclass = 'MLU_Banner_Display']"> </xsl:template>
    <xsl:template match="p[@outputclass = 'MLU_Banner_Color']"> </xsl:template>

    <xsl:template match="p[@outputclass = 'MLU_Intro']">
        <p><xsl:apply-templates/></p>
    </xsl:template>

    <xsl:template match="p[@outputclass = 'MLU_Directions']">
        <directionText>
            <text>
                <xsl:value-of select="//p[@outputclass = 'MLU_Directions']"/>
            </text>
        </directionText>
    </xsl:template>
    <xsl:template match="title[@outputclass = 'MLU-Body']"> </xsl:template>
    <xsl:template match="title"> </xsl:template>
    <xsl:template match="ph">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="p[@outputclass = 'MLU_Item_Button']"> </xsl:template>
    <xsl:template match="p[@outputclass = 'MLU_Item_Title_Position']"> </xsl:template>
    <xsl:template match="bodydiv[@outputclass = 'Item_Defaults']"> </xsl:template>
    <xsl:template match="bodydiv">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="p">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template>

    <xsl:template match="image"></xsl:template>
    <xsl:template match="@MLU_Banner_Display"> </xsl:template>
    <xsl:template match="@class">
        <!--<xsl:apply-templates/>-->
    </xsl:template>
    <xsl:template match="ul">
        <ul>
            <xsl:apply-templates/>
        </ul>
    </xsl:template>
    <xsl:template match="ol">
        <ol>
            <xsl:apply-templates/>
        </ol>
    </xsl:template>
    <xsl:template match="li">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>
    <xsl:template match="ph[@outputclass = 'Bold']">
        <strong>
            <xsl:apply-templates/>
        </strong>
    </xsl:template>
</xsl:stylesheet>
2
Tomalak On

You currently have two templates that match="p". The second one is being used.

In XSLT, just like in CSS, if two rules can match a given node, the rule defined last wins.

Steps to solve:

  • Either remove the second template, or
  • reorder your templates, or
  • let one of them match something more specific than p