Prashant
Prashant

Reputation: 31

Converting XML using XSL (having nested tags)

I have an XML something like...

<?xml version='1.0' encoding='utf-8'?>
<HL7Message>
    <MSH>
        <MSH.1>|</MSH.1>
        <MSH.2>^~\&amp;</MSH.2>
        <MSH.3>
            <MSH.3.1>ST01</MSH.3.1>
        </MSH.3>
        <MSH.4>
            <MSH.4.1>A</MSH.4.1>
        </MSH.4>
        <MSH.5>
            <MSH.5.1>HC</MSH.5.1>
            <MSH.5.2>HC2</MSH.5.2>
        </MSH.5>
    </MSH>
</HL7Message>

which I want to convert into following format so that it can be accepted by solr..

<add>
<doc>
  <field name="MSH.1">|</field>
  <field name="MSH.2">^~\&amp;</field>
  <field name="MSH.3.1">ST01</field>
  <field name="MSH.4.1">A</field>
  <field name="MSH.5.1">HC</field>
  <field name="MSH.5.2">HC2</field>
</doc>
</add>

Now I have created one XSLT as below..

<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output method="xml" encoding="utf-8" indent="yes"/> 
<xsl:strip-space elements="*" />
<xsl:template match="MSH">
<add><doc>
<xsl:apply-templates select="MSH"/>
<xsl:for-each select="*">
<xsl:element name="field">

<xsl:attribute name="name"><xsl:value-of select="node()"/</xsl:attribute>
<xsl:value-of select="."/>
</xsl:element>

</xsl:for-each>
</doc></add>
</xsl:template>
</xsl:stylesheet>

but It is right now converting to following format..

<add>
<doc>
  <field name="MSH.1">|</field>
  <field name="MSH.2">^~\&amp;</field>
  <field name="MSH.3">ST01</field>
  <field name="MSH.4">A</field>
  ***<field name="MSH.5">HCHC2</field>***
</doc>
</add>

as we can see MSH 5.1 and MSH 5.2 are getting combined which is other than I am expecting..

If anyone can help or guide me where I am making mistake, it would be greatly appreciated.. Thanks in advance.

Upvotes: 0

Views: 66

Answers (1)

Tim C
Tim C

Reputation: 70618

Instead of selecting just the direct child elements of the MSH element, you should probably select any descendant elements which don't have any child elements themselves.

<xsl:for-each select=".//*[not(*)]">

So, this will select MSH.5.1 and MSH.5.2 for example, but not MSH.5 itself.

Try this XSLT (which I have also simplified with Attribute Value Templates to create the @name attribute)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output method="xml" encoding="utf-8" indent="yes"/> 
<xsl:strip-space elements="*" />

<xsl:template match="MSH">
  <add>
  <doc>
    <xsl:for-each select=".//*[not(*)]">
      <field name="{name()}">  
        <xsl:value-of select="."/>
      </field>
    </xsl:for-each>
  </doc>
  </add>
</xsl:template>
</xsl:stylesheet>

Upvotes: 1

Related Questions