Home > Net >  How to transform xml using XSLT in Visual Studio?
How to transform xml using XSLT in Visual Studio?

Time:02-01

Input xml data looks like this:

<Item key="">
  <Adress>
    <Template key="01,09-10,21">
      <Channel>
        <Template key="1-3"/>
      </Channel>
    </Template>
  </Adress>
</Item> 

First, I wrote an Identity template that copies all the tags and their attributes sequentially to the output xml (the input and output file are the same). Then I renamed the 'Template' tag to 'Item' so the stylesheet looks like this:

<?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" omit-xml-declaration="yes"/>
  
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Template">
        <Item>
            <xsl:apply-templates select="@*|node()"/>
        </Item>
    </xsl:template>

</xsl:stylesheet>

How do I write the style file so that the output xml looks like this:

<Item key="">
  <Adress>
    <Item key="01">
      <Channel>
        <Item key="1"/>
        <Item key="2"/>
        <Item key="3"/>
      </Channel>
    </Item>
    <Item key="09">
      <Channel>
        <Item key="1"/>
        <Item key="2"/>
        <Item key="3"/>
      </Channel>
    </Item> 
    <Item key="10">
      <Channel>
        <Item key="1"/>
        <Item key="2"/>
        <Item key="3"/>
      </Channel>
    </Item>
    <Item key="21">
      <Channel>
        <Item key="1"/>
        <Item key="2"/>
        <Item key="3"/>
      </Channel>
    </Item>
  </Adress>
</Item>

XSLT version 1.0, Visual Studio 2017

CodePudding user response:

You said you wanted XSLT 1.0, but your example stylesheet was XSLT 2.0 (which you need for regex based functions)

This is one possible XSLT 2 solution that first tokenize() by the , and then evaluates whether the values are a range of numbers that need expanding.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Template">
        <xsl:variable name="context" select="*"/>
        <xsl:copy>
            <!-- first split the comma separated values -->
            <xsl:for-each select="tokenize(@key, ',')">
                <!-- determine whether there is a range of key values or a single value -->
                <xsl:variable name="keys" as="item()*">  
                    <xsl:choose>
                        <xsl:when test="matches(., '\d -\d ')">
                            <xsl:variable name="range" select="tokenize(., '-')"/>
                            <xsl:sequence select="xs:integer(head($range)) to xs:integer(tail($range))"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:sequence select="."/>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:variable>
     
                <xsl:for-each select="$keys">
                    <Item key="{xs:integer(.)}">
                        <xsl:apply-templates select="$context"/>
                    </Item>
                </xsl:for-each>
                
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>

The only thing that isn't clear is whether or not you would want the leading zeros preserved for the first level and not the second. This output turns them all into integers and will have Item/@key values without a leading zero. Additional logic could be applied, but would need to know when to preserve and format with leading zeros and when not to do so.

  •  Tags:  
  • Related