我们有xml文档,其中包含许多标记节点,如isProduct,isActive,isMandatory,其中节点文本可能为True或False。
需要操纵文档并保留其结构,但将上述节点转换为如下所示的语言表示:
< isProduct >True</ isProduct > ===> <Type>Product<Type>
< isProduct >False</ isProduct > ===> <Type/>
其他标志节点也一样。
我们正在寻求一种可扩展且可扩展的解决方案,可在部署后以最小的摩擦配置。
可扩展;我们的意思是会有更多的案件;比如表示状态的2个标志;即isEmployee和isCustomer在文档中用于表示4种不同的命名事物。因此,4种可能的组合应该只转换成一个字符串,如“员工”,“客户”,“客户 - 员工”或“无”。
可扩展;我们的意思是它可用于处理任何XML文档,而无需事先了解其架构,也不会限制文档大小。
我们确实理解这可能是使用XSLT完成的,我们是否可以编写一个接受任何文档的XSLT并生成添加或更新其他节点的同一文档?
答案 0 :(得分:2)
假设输入如下:
<gizmo>
<isProduct>True</isProduct>
<isFoo>False</isFoo>
<isBar>True</isBar>
</gizmo>
通用方法是:
<xsl:template match="gizmo">
<xsl:copy>
<xsl:apply-templates select="*" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[substring(local-name(), 1, 2) = 'is']">
<Type>
<xsl:if test=". = 'True'">
<xsl:value-of select="substring-after(local-name(), 'is')" />
</xsl:if>
</Type>
</xsl:template>
产生:
<gizmo>
<Type>Product</Type>
<Type />
<Type>Bar</Type>
</gizmo>
更通用的方法使用(严重)修改的身份变换:
<!-- the identity template... well, sort of -->
<xsl:template match="node() | @*">
<xsl:copy>
<!-- all element-type children that begin with 'is' -->
<xsl:variable name="typeNodes" select="
*[substring(local-name(), 1, 2) = 'is']
" />
<!-- all other children (incl. elements that don't begin with 'this ' -->
<xsl:variable name="otherNodes" select="
@* | node()[not(self::*) or self::*[substring(local-name(), 1, 2) != 'is']]
" />
<!-- identity transform all the "other" nodes -->
<xsl:apply-templates select="$otherNodes" />
<!-- collapse all the "type" nodes into a string -->
<xsl:if test="$typeNodes">
<Type>
<xsl:variable name="typeString">
<xsl:apply-templates select="$typeNodes" />
</xsl:variable>
<xsl:value-of select="substring-after($typeString, '-')" />
</Type>
</xsl:if>
</xsl:copy>
</xsl:template>
<!-- this collapses all the "type" nodes into a string -->
<xsl:template match="*[substring(local-name(), 1, 2) = 'is']">
<xsl:if test=". = 'True'">
<xsl:text>-</xsl:text>
<xsl:value-of select="substring-after(local-name(), 'is')" />
</xsl:if>
</xsl:template>
<!-- prevent the output of empty text nodes -->
<xsl:template match="text()">
<xsl:if test="normalize-space() != ''">
<xsl:value-of select="." />
</xsl:if>
</xsl:template>
上面提取任何XML输入并输出相同的结构,只有名为<is*>
的元素作为划线分隔的字符串折叠到单个<Type>
节点中:
<!-- in -->
<foo>
<fancyNode />
<gizmo>
<isProduct>True</isProduct>
<isFoo>False</isFoo>
<isBar>True</isBar>
</gizmo>
</foo>
<!-- out -->
<foo>
<fancyNode />
<gizmo>
<Type>Product-Bar</Type>
</gizmo>
</foo>
答案 1 :(得分:1)
以下是基于身份转换的XSLT解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="isProduct">
<xsl:choose>
<xsl:when test=". = 'True'"><Type>Product</Type></xsl:when>
<xsl:otherwise><Type/></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>