1

I am applying concat function of XPath 2.0 to concatenate two xml elements. It concatenates them but gives the output in text form. I am using XSLT for this transformation.

Note: I have studied about it on internet, concat function by default converts the data into text format, is there any way to bypass it so that after concatenation data can be still in XML form.

Input XML:

<?xml version="1.0"?><?xml-stylesheet type="text/xsl"?>

    <jsonObject>
       <alarm>
          <groups>1</groups>
          <typeKey>FIRE</typeKey>
          <longitude>65656</longitude>
          <victim>2</victim>
          <letitude>6566</letitude>
       </alarm>
       <alarm2>
       <data>Stewart</data>
      <data1>John</data1>
      </alarm2>
    </jsonObject>

Input XSLT:

<?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" indent="yes" encoding="UTF-8"/>

     <xsl:template match="//jsonObject/alarm">


        <Latitude><xsl:value-of select="letitude"/></Latitude>
        <Combine><xsl:value-of select="concat(//alarm,//alarm2) "/></Combine>


    </xsl:template>
    </xsl:stylesheet>

Current Result:

<?xml version="1.0" encoding="UTF-8"?>
   <Latitude>6566</Latitude>
<Combine>
      1
      FIRE
      65656
      2
      6566

   Stewart
  John
  </Combine>

Expected Result:

<?xml version="1.0" encoding="UTF-8"?>
       <Latitude>6566</Latitude>
    <Combine>
              <groups>1</groups>
              <typeKey>FIRE</typeKey>
              <longitude>65656</longitude>
              <victim>2</victim>
              <letitude>6566</letitude>
              <data>Stewart</data>
          <data1>John</data1>
      </Combine>
Umair Khalid
  • 569
  • 1
  • 4
  • 24

2 Answers2

1

concat () only operates on text. Therefore, it takes the text value of each and then concatenates them together. You don't concatenate nodes, Instead, you need to copy each of them:

<Combine><xsl:copy-of select="//alarm/*"/><xsl:copy-of select="//alarm2/*"/></Combine>
Mike
  • 2,721
  • 1
  • 15
  • 20
1

As described in another answer, you should be using xsl:copy-of here.

However, an alternate approach is to use a template based solution, building on top of the XSLT identity template.

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />

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

  <xsl:template match="alarm">
      <Latitude><xsl:value-of select="letitude"/></Latitude>
      <Combine>
        <xsl:apply-templates />
        <xsl:apply-templates select="../alarm2/*" />
      </Combine>
  </xsl:template>

  <xsl:template match="alarm2" />

</xsl:stylesheet>

So, you transform the alarm element by converting it into a Combine element, and also adding in the children of alarm2. A second template matches alarm2 itself to stop it being output twice. The identity template is then used to copy all other nodes in the XML.

Tim C
  • 70,053
  • 14
  • 74
  • 93