如何在 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
没有前导零的值。可以应用其他逻辑,但需要知道何时使用前导零保留和格式化以及何时不这样做。
输入 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
没有前导零的值。可以应用其他逻辑,但需要知道何时使用前导零保留和格式化以及何时不这样做。