使用XSL将XML转换为XAML

时间:2013-02-26 15:04:29

标签: c# xml xaml xslt

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

1 个答案:

答案 0 :(得分:5)

这种转变可以完成。我假设你使用的是XSLT 1.0,XSLT 2.0中的解决方案会更短(因为我必须做的递归模板才能实现2)。我也假设:

  1. Visible的可能值为:'True','False',转换为'Visible'和'Hidden'。
  2. BorderThickness属性按以下顺序构建:left,top,right,bottom。此外,如果找不到某些边框属性,则其值默认为零。
  3. 代码的想法是手动匹配每个属性并将其值替换为正确的值。因为我不知道遵循所有属性的逻辑(除了我在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>
      

      将属性font-size映射到FontSize。

    • 您可以通过匹配名称和值来更改属性的名称和值,如:

      <xsl:template match="@font-style[. = 'Regular']">
              <xsl:attribute name="FontStyle">Normal</xsl:attribute>
      </xsl:template>
      

      匹配所有属性,例如font-style ='regular',并将它们转换为FontStyle ='normal'。