1

假设我在 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"
4

1 回答 1

5

这种转变是可以做到的。我假设您使用的是 XSLT 1.0,XSLT 2.0 中的解决方案会更短(因为我必须使用递归模板来实现 2.)。我还假设:

  1. Visible 的可能值是:'True'、'False' 转换为 'Visible' 和 'Hidden'。
  2. 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'。

于 2013-02-26T16:22:57.220 回答