如何在 Visual Studio 中使用 XSLT 转换 xml?

How to transform xml using XSLT in Visual Studio?

输入 xml 数据如下所示:

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

首先,我编写了一个标识模板,将所有标签及其属性按顺序复制到输出xml(输入和输出文件相同)。然后我将 'Template' 标记重命名为 'Item',因此样式表如下所示:

<?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>

如何编写样式文件使输出 xml 如下所示:

<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 版本 1.0,Visual Studio 2017

您说您想要 XSLT 1.0,但您的示例样式表是 XSLT 2.0(基于正则表达式的函数需要它)

这是一个可能的 XSLT 2+ 解决方案,首先 tokenize() ,,然后评估这些值是否是需要扩展的数字范围。

<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>

唯一不清楚的是您是否希望为第一级而不是第二级保留前导零。此输出将它们全部转换为整数,并且将具有 Item/@key 没有前导零的值。可以应用其他逻辑,但需要知道何时使用前导零保留和格式化以及何时不这样做。