使用XSL将XML转换为XAML
本文关键字:XAML 转换 XML XSL 使用 | 更新日期: 2023-09-27 18:01:07
假设我在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>
我需要将xml代码转换为XAML。预期的最终结果应该是这样的:
<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>
使用xsl样式表可以进行这种转换吗?
我特别问这样的转换:
来自
border-left="1"
border-top="1"
border-right="1"
border-bottom="1"
至
BorderThickness="1,1,1,1"
或来自
visible="True"
至
Visibility="Visible"
可以完成此转换。我假设您使用的是XSLT1.0,XSLT2.0中的解决方案会更短(因为我必须使用递归模板才能实现2(
- Visible的可能值为:"True"、"False",它们被转换为"Visible"answers"Hidden">
- BorderThickness属性按以下顺序构建:左、上、右、下。此外,如果找不到某些边界属性,则其值默认为零
代码的思想是手动匹配每个属性,并将其值替换为正确的值。因为我不知道所有属性后面的逻辑(除了我在1中假设的位。和2.(转换仅限于给定的XML,但我希望它能让您了解如何实现您想要做的事情
<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>
代码的主要思想是:
您可以使用以下模板更改元素的名称:
<!-- Transform PanelWrapper to WrapPannel --> <xsl:template match="PanelWrapper"> <WrapPanel> <xsl:apply-templates select="@*|*" /> </WrapPanel> </xsl:template>
它匹配任何名为PanelWrapper的元素,并将其名称更改为WrapPannel。
您可以使用以下模板更改属性的名称并保持其值:
<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>
它匹配所有属性,如font style="regular",并将它们转换为FontStyle="normal"。