Search code examples
xmlxsltxalan

XSLT an XML such that everything is the same except one section


Just a quick question. I have one XML and I was hoping to tranform only a section of it without changing anything else. Here is a quick example of what I am looking to do:

Input:

<?xml version="1.0" encoding="UTF-8"?>
<dita xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/ditabase.xsd">
    <topic id="abc">
        <title>Sample XML</title>
        <body>
         <section id="a">
            <p> Hello section A </p>
         </section>
         <section id="b">
            <p> General Content </p>
         </section>
         <section id="c">
            <p> Hi thank you for coming from $state </p>
         </section>
        </body>
    </topic>
</dita>

Output

<?xml version="1.0" encoding="UTF-8"?>
<dita xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/ditabase.xsd">
    <topic id="abc">
        <title>Sample XML</title>
        <body>
         <section id="a">
            <p> Hello section A </p>
         </section>
         <section id="b">
            <p> General Content </p>
         </section>
         <section id="c" audience = "WA">
            <p> Hi thank you for coming from WA </p>
         </section>
             <section id="c" audience = NY">
            <p> Hi thank you for coming from NY </p>
         </section>
             <section id="c" audience = "AL">
            <p> Hi thank you for coming from AL </p>
         </section>
             <section id="c" audience = "GA">
            <p> Hi thank you for coming from GA </p>
         </section>
            ...
            <!--Continue for the rest of the states--> 
            ...
        </body>
    </topic>
</dita>

I am using the XALAN processor if that could help. Thanks a lot in advance :D


Solution

  • I propose that you change a little bit the format of the XML to make the solurion simpler:

    Instead of:

    <p> Hi thank you for coming from $state </p>
    

    use:

    <p> Hi thank you for coming from <state/> </p>
    

    For this format, the following transformation:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:my="my:my"
     >
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <my:states>
       <state name="WA"/>
       <state name="NY"/>
       <state name="AL"/>
       <state name="GA"/>
     </my:states>
    
     <xsl:variable name="vStates" select="document('')/*/my:states/*"/>
    
     <xsl:template match="node()|@*">
      <xsl:param name="pState"/>
      <xsl:copy>
       <xsl:apply-templates select="node()|@*">
        <xsl:with-param name="pState" select="$pState"/>
       </xsl:apply-templates>
      </xsl:copy>
     </xsl:template>
    
     <xsl:template match="section[descendant::state]">
       <xsl:variable name="vSect" select="."/>
    
       <xsl:for-each select="$vStates">
         <xsl:apply-templates select="$vSect" mode="generate">
           <xsl:with-param name="pState" select="@name"/>
         </xsl:apply-templates>
       </xsl:for-each>
     </xsl:template>
    
     <xsl:template match="section" mode="generate">
      <xsl:param name="pState"/>
    
      <xsl:copy>
       <xsl:copy-of select="@*"/>
       <xsl:attribute name="audience">
        <xsl:value-of select="$pState"/>
       </xsl:attribute>
       <xsl:apply-templates>
        <xsl:with-param name="pState" select="$pState"/>
       </xsl:apply-templates>
      </xsl:copy>
     </xsl:template>
    
     <xsl:template match="state">
      <xsl:param name="pState"/>
      <xsl:value-of select="$pState"/>
     </xsl:template>
    </xsl:stylesheet>
    

    when applied on the (slightly modified) provided XML document:

    <dita xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/ditabase.xsd">
        <topic id="abc">
            <title>Sample XML</title>
            <body>
             <section id="a">
                <p> Hello section A </p>
             </section>
             <section id="b">
                <p> General Content </p>
             </section>
             <section id="c">
                <p> Hi thank you for coming from <state/> </p>
             </section>
            </body>
        </topic>
    </dita>
    

    produces the wanted, correct result:

    <dita xsi:noNamespaceSchemaLocation="../../../xsd/ditabase.xsd" xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <topic id="abc">
            <title>Sample XML</title>
            <body>
             <section id="a">
                <p> Hello section A </p>
             </section>
             <section id="b">
                <p> General Content </p>
             </section>
             <section id="c" audience="WA">
                <p> Hi thank you for coming from WA </p>
             </section>
    <section id="c" audience="NY">
                <p> Hi thank you for coming from NY </p>
             </section>
    <section id="c" audience="AL">
                <p> Hi thank you for coming from AL </p>
             </section>
    <section id="c" audience="GA">
                <p> Hi thank you for coming from GA </p>
             </section>
            </body>
        </topic>
    </dita>