简体   繁体   中英

Beginner XML to XML dynamic transformation using xslt

I am new to XSLT, I need to transform an xml file to another xml file using xslt.

The input file is as below:

<root type="object">
    <items type="array">
        <item type="object">
            <original_file_name type="string">filename-m.mp3</original_file_name>
            <description type="string">some description text</description>
            <created_at type="string">2017-02-20T20:52:52Z</created_at>
            <metadata type="object">
                <guest type="string">guestname here</guest>
                <webInfo type="string">http://abc</webInfo>
                <title type="string">title text testing</title>
                <airDate type="string">2017-02-21</airDate>
            </metadata>
            <status type="string">live</status>
            <asset_type type="string">video</asset_type>
            <player_id type="string">391e099a718f4a62b44c78f97f85ecde</player_id>
            <name type="string">title</name>
        </item>
        <item>
        .....
        </item>
    </items>
</root>

Need to transform the above xml to the below format:

<?xml version="1.0" encoding="utf-8"?>
<assets>
    <item>
        <original_file_name>filename-m.mp3</original_file_name>
        <description>some description text</description>
        <created_at>2017-02-20T20:52:52Z</created_at>
        <guest>guestname here</guest>
        <webInfo>http://abc</webInfo>
        <title>title text testing</title>
        <airDate>2017-02-21</airDate>       
        <status>live</status>
        <asset_type>video</asset_type>
        <player_id>391e099a718f4a62b44c78f97f85ecde</player_id>
        <name>title</name>
    </item>
    <item>
    .....
    </item>
</assets>

Transformation rules are as follows: 1) Replace <root><items>...</items></root> to <assets>...</assets> 2) Remove all attributes 3) Remove the metadata tag and bring the child node of metadata to child node of item tag. 4) Child node of metadata tag is dynamic ie the number of child node and the names of child nodes may vary.

I was able to solve first two points ..need solution for third and fourth point. Below is my code:

<?xml version="1.0" encoding="utf-8" ?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">
  <assets>
      <xsl:for-each select="root/items/item">
          <item>
              <original_file_name>
              <xsl:value-of select="original_file_name"/>
              </original_file_name>
              <description>
              <xsl:value-of select="description"/>
              </description>              
          </item>
      </xsl:for-each>     
  </assets>
  </xsl:template>  
</xsl:stylesheet> 

Thanks a lot for your immediate response The code which you sent work fine for me but when we have the below line it throws an error. It works fine when this line is removed. For this line <xsl:strip-space elements="*" /> I am getting the below error White space cannot be stripped from input documents that have already been loaded. Provide the input document as an XmlReader instead.

I have one more doubt, what to do if we want to have some child nodes not all child nodes (selectively) for example:

<root type="object">
    <items type="array">
        <item type="object">
            <elem1></elem1>
            <elem2></elem2>
            <elem3></elem3>
            <elem4></elem4>
            <elem5></elem5>
            <elem6></elem6>
            <elem7></elem7>
        </item>
    </items>
</root>

Output should be as below:

<assets>
    <item>
        <elem1></elem1>
        <elem3></elem3>
        <elem6></elem6>
        <elem7></elem7>
    </item>
</assets>

In problems like this, it is nearly always best to start with the identity template

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

This will copy all nodes and elements as-is, so you only need to worry about writing templates for things you do need to change.

Having said that, you need to remove attributes, so you would actually need to change the identity template here to remove the match of attributes @* and move that to a separate template instead.

<xsl:template match="@*" />

To remove the metadata tag but keep its children, add a template like so

<xsl:template match="metadata">
    <xsl:apply-templates select="node()"/>
</xsl:template>

The only other change would be to replace your xsl:for-each with an xsl:apply-templates instead to allow the other templates to do their work.

Try this XSLT

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

    <xsl:strip-space elements="*" />

    <xsl:template match="/">
        <assets>
            <xsl:apply-templates select="root/items/item" />     
        </assets>
    </xsl:template>  

    <xsl:template match="metadata">
        <xsl:apply-templates select="node()"/>
    </xsl:template>

    <xsl:template match="@*" />

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

Learn to use template matching and apply-templates:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>

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

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

    <xsl:template match="items | metadata">
        <xsl:apply-templates/>
    </xsl:template>
</xsl:transform>

Online at http://xsltransform.net/bwdwsK .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM