Reputation: 4882
Lets say i have the following code snippet in xml:
<PanelWrapper id="RootPanel"
dock="Fill"
width="1092"
height="605"
backcolor="Transparent"
visible="True">
<ButtonWrapper id="button1"
dock="Left"
text="TestButton"
width="75"
height="605"
border-left="1"
border-top="1"
border-right="1"
border-bottom="1"
font-name="Tahoma"
font-size="9"
font-style="Regular">
</ButtonWrapper>
</PanelWrapper>
i need to transform the xml code to XAML. The expected endresult should look like this:
<WrapPanel Name="RootPanel"
DockPanel.Dock="Left, Right, Top, Bottom"
Width="1092" Height="605"
Background="Transparent"
Visibility="Visible">
<Button Name="button1"
DockPanel.Dock ="Left"
Content="TestButton"
Width="75"
Height="605"
BorderThickness="1,1,1,1"
FontFamily="Tahoma"
FontSize="9"
FontStyle="Normal">
</Button>
</WrapPanel>
is this transformation possible with an xsl stylesheet?
I'm asking especially about transformations like these:
from
border-left="1"
border-top="1"
border-right="1"
border-bottom="1"
to
BorderThickness="1,1,1,1"
or from
visible="True"
to
Visibility="Visible"
Upvotes: 1
Views: 3342
Reputation: 1920
This transformation can be done. I am assuming that you are using XSLT 1.0, the solution in XSLT 2.0 would be shorter (because of the recursive template I had to do to achieve 2.). I am assuming also that:
The idea of the code is matching manually each attribute and replacing its value to the correct ones. Because I do not know the logic which follow all the attributes (except the bit that I assumed in 1. and 2.) the transformation is limited to the given XML, however I hope it gives you the idea of how to achieve what you are trying to do.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<!-- Ignore attributes by default, so we can have more control
about unhandled attributes -->
<xsl:template match="@*" />
<!-- Transform PanelWrapper to WrapPannel -->
<xsl:template match="PanelWrapper">
<WrapPanel>
<xsl:apply-templates select="@*|*" />
</WrapPanel>
</xsl:template>
<!-- Transform ButtonWrapper to Button -->
<xsl:template match="ButtonWrapper">
<Button>
<xsl:apply-templates select="@*" />
</Button>
</xsl:template>
<!-- Map id attribute to Name -->
<xsl:template match="@id">
<xsl:attribute name="Name">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<!-- Map @dock = 'Fill' to @dock = 'Left, Right...etc' -->
<xsl:template match="@dock[. = 'Fill']">
<xsl:attribute name="DockPanel.Dock">
<xsl:value-of select="'Left, Right, Top, Bottom'" />
</xsl:attribute>
</xsl:template>
<!-- For every other @dock value, map @dock to DockPanel.dock
and copy value -->
<xsl:template match="@dock">
<xsl:attribute name="DockPanel.Dock">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<!-- Map width attribute to Width -->
<xsl:template match="@width">
<xsl:attribute name="Width">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<!-- Map height attribute to Height -->
<xsl:template match="@height">
<xsl:attribute name="Height">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<!-- Map backcolor to Background -->
<xsl:template match="@backcolor">
<xsl:attribute name="Background">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<!-- Map visible attribute to Visibility -->
<xsl:template match="@visible[. = 'True']">
<xsl:attribute name="Visibility">visible</xsl:attribute>
</xsl:template>
<xsl:template match="@visible[. = 'False']">
<xsl:attribute name="Visibility">hidden</xsl:attribute>
</xsl:template>
<!-- Map text attribute to content -->
<xsl:template match="@text">
<xsl:attribute name="Content">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<!-- Build the border attribute -->
<xsl:template match="@*[starts-with(local-name(), 'border-')][1]">
<xsl:attribute name="BorderThickness">
<!-- Print the border-elements in a comma separated list (non-defined attributes default
to zero) -->
<xsl:call-template name="border-print" />
</xsl:attribute>
</xsl:template>
<!-- Recursive template to group borders in BorderThickness -->
<xsl:template name="border-print">
<xsl:param name="string" select="'left top right bottom'" />
<xsl:param name="parent" select=".." />
<xsl:param name="not-first" select="false()" />
<xsl:if test="$string != ''">
<!-- Obtain next direction -->
<xsl:variable name="direction" select="normalize-space(substring($string, 1, 6))" />
<xsl:variable name="attr" select="$parent/@*[local-name() = concat('border-', $direction)]" />
<!-- Print comma if not the first element -->
<xsl:if test="$not-first"><xsl:text>,</xsl:text></xsl:if>
<!-- Print zero if the attribute cannot be found -->
<xsl:choose>
<!-- Attribute found : print -->
<xsl:when test="$attr">
<xsl:value-of select="$attr" />
</xsl:when>
<!-- Attribute not found: print 0 -->
<xsl:otherwise>
<xsl:text>0</xsl:text>
</xsl:otherwise>
</xsl:choose>
<!-- Recurse -->
<xsl:call-template name="border-print">
<xsl:with-param name="string" select="substring($string, 7)" />
<xsl:with-param name="parent" select="$parent" />
<xsl:with-param name="not-first" select="true()" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="@*" mode="print-border">
<xsl:value-of select="concat(., ',')" />
</xsl:template>
<xsl:template match="@border-bottom" mode="print-border">
<xsl:value-of select="." />
</xsl:template>
<!-- Map font properties -->
<xsl:template match="@font-name">
<xsl:attribute name="FontFamily">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="@font-size">
<xsl:attribute name="FontSize">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="@font-style[. = 'Regular']">
<xsl:attribute name="FontStyle">Normal</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
The main ideas of the code are:
You can change the name of an element by using templates like:
<!-- Transform PanelWrapper to WrapPannel -->
<xsl:template match="PanelWrapper">
<WrapPanel>
<xsl:apply-templates select="@*|*" />
</WrapPanel>
</xsl:template>
which matches any element named PanelWrapper and changes its name to WrapPannel.
You can change the name of an attribute and keeping its value by using templates like:
<xsl:template match="@font-size">
<xsl:attribute name="FontSize">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
which maps the attribute font-size to FontSize.
You can change the name and value of an attribute by matching its name and value like:
<xsl:template match="@font-style[. = 'Regular']">
<xsl:attribute name="FontStyle">Normal</xsl:attribute>
</xsl:template>
which matches all attributes such as font-style = 'regular' and transform them to FontStyle = 'normal'.
Upvotes: 5