Search code examples
xmlxslttransformationmode

How to transform xml block?


I am new at XSL and I couldn't find anywhere like following case. I want to transform source.xml to target.xml. I have use mode "group" but it didn't work for me (probably I couldn't use it properly)

source.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>

<PersonBody>

    <Person>
        <D>Name</D>
        <D>Surname</D>
        <D>Id</D>
    </Person>

    <PersonValues>
        <D>Michael</D>
        <D>Jackson</D>
        <D>01</D>
    </PersonValues>

    <PersonValues>
        <D>James</D>
        <D>Bond</D>
        <D>007</D>
    </PersonValues>

    <PersonValues>
        <D>Kobe</D>
        <D>Bryant</D>
        <D>24</D>
    </PersonValues>

</PersonBody>

target.xml:

<PersonBody>
  <AllValues>
    <Name>
      <D>Michael</D>
      <D>James</D>
      <D>Kobe</D>
    </Name>
    <Surname>
      <D>Jackson</D>
      <D>Bond</D>
      <D>Bryant</D>
    </Surname>
    <Id>
      <D>01</D>
      <D>007</D>
      <D>24</D>
    </Id>
  </AllValues>
</PersonBody>

EDIT : I have asked another question because the output is changed. You can find the other question from here


Solution

  • Give this a try:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
      <xsl:key name="kColumnValue" match="PersonValues/*" 
               use="count(preceding-sibling::*)" />
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="/*">
        <xsl:copy>
          <AllValues>
            <xsl:apply-templates select="Person/*" />
          </AllValues>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="Person/*">
        <xsl:element name="{.}">
          <xsl:apply-templates select="key('kColumnValue', position() - 1)" />
        </xsl:element>
      </xsl:template>
    </xsl:stylesheet>
    

    When run on your sample XML, the result is:

    <PersonBody>
      <AllValues>
        <Name>
          <D>Michael</D>
          <D>James</D>
          <D>Kobe</D>
        </Name>
        <Surname>
          <D>Jackson</D>
          <D>Bond</D>
          <D>Bryant</D>
        </Surname>
        <Id>
          <D>01</D>
          <D>007</D>
          <D>24</D>
        </Id>
      </AllValues>
    </PersonBody>