给出以下Xml:
<record>
<category>Sport/Racket Sports/Tennis</category>
<category>Sport/Racket Sports/Badminton</category>
</record>
我正在尝试拆分类别,以便生成以下Xml:
<add>
<doc>
<field name="category_0">Sport</field>
<field name="category_1">Sport/Racket Sports</field>
<field name="category_2">Sport/Racket Sports/Tennis</field>
<field name="category_2">Sport/Racket Sports/Badminton</field>
</doc>
</add>
我已经设法生产了几乎就在那里的东西..我现在需要一种方法来删除重复的东西?有什么想法吗?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="record">
<add>
<doc>
<xsl:for-each select="category[. != '']">
<xsl:call-template name="split-cats">
<xsl:with-param name="prefix" select="''"/>
<xsl:with-param name="text" select="."/>
<xsl:with-param name="level" select="number(0)"/>
</xsl:call-template>
</xsl:for-each>
</doc>
</add>
</xsl:template>
<xsl:template name="split-cats">
<xsl:param name="text" select="."/>
<xsl:param name="prefix"/>
<xsl:param name="level" select="0"/>
<xsl:choose>
<xsl:when test="contains($text, '/')">
<field>
<xsl:attribute name="name">
<xsl:text>category_</xsl:text><xsl:value-of select="$level"/>
</xsl:attribute>
<xsl:value-of select="concat($prefix, substring-before($text, '/'))"/>
</field>
<xsl:call-template name="split-cats">
<xsl:with-param name="prefix" select="concat($prefix, concat(substring-before($text, '/'), '/'))"/>
<xsl:with-param name="text" select="substring-after($text, '/')"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<field>
<xsl:attribute name="name">
<xsl:text>category_</xsl:text><xsl:value-of select="$level"/>
</xsl:attribute>
<xsl:value-of select="concat($prefix, $text)"/>
</field>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
此模板生成:
<add>
<doc>
<field name="category_0">Sport</field>
<field name="category_1">Sport/Racket Sports</field>
<field name="category_2">Sport/Racket Sports/Tennis</field>
<field name="category_0">Sport</field>
<field name="category_1">Sport/Racket Sports</field>
<field name="category_2">Sport/Racket Sports/Badminton</field>
</doc>
</add>
您可以看到其中有Sport
和Sport/Racket Sports
两次:(
仅供参考:我需要能够使用XSLT 1.0
执行此操作由于
戴夫
答案 0 :(得分:1)
这是一个直接的方法,只需在代码创建的结果上使用Muenchian分组插入第二个转换步骤:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
<xsl:output indent="yes"/>
<xsl:key name="k1" match="cats/field" use="."/>
<xsl:template match="record">
<xsl:variable name="cats">
<cats>
<xsl:for-each select="category[. != '']">
<xsl:call-template name="split-cats">
<xsl:with-param name="prefix" select="''"/>
<xsl:with-param name="text" select="."/>
<xsl:with-param name="level" select="0"/>
</xsl:call-template>
</xsl:for-each>
</cats>
</xsl:variable>
<add>
<doc>
<xsl:copy-of select="exsl:node-set($cats)/cats/field[generate-id() = generate-id(key('k1', .)[1])]"/>
</doc>
</add>
</xsl:template>
<xsl:template name="split-cats">
<xsl:param name="text" select="."/>
<xsl:param name="prefix"/>
<xsl:param name="level" select="0"/>
<xsl:choose>
<xsl:when test="contains($text, '/')">
<field>
<xsl:attribute name="name">
<xsl:text>category_</xsl:text><xsl:value-of select="$level"/>
</xsl:attribute>
<xsl:value-of select="concat($prefix, substring-before($text, '/'))"/>
</field>
<xsl:call-template name="split-cats">
<xsl:with-param name="prefix" select="concat($prefix, concat(substring-before($text, '/'), '/'))"/>
<xsl:with-param name="text" select="substring-after($text, '/')"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<field>
<xsl:attribute name="name">
<xsl:text>category_</xsl:text><xsl:value-of select="$level"/>
</xsl:attribute>
<xsl:value-of select="concat($prefix, $text)"/>
</field>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
使用exsl:node-set
但是,如果您在浏览器中定位XSLT 1.0,那么对于IE / MSXML,您需要使用http://dpcarlisle.blogspot.com/2007/05/exslt-node-set-function.html中显示的脚本来修复它。
答案 1 :(得分:1)
在不使用扩展功能的情况下实现此目的的另一种方法(但不一定能像使用Muenchian分组一样高效)是添加一个检查来比较以前的类别记录,看看它们是否以您即将使用的字符串开头
<xsl:if test="not(/record/category
[. != '']
[position() < $pos]
[substring(., 1, string-length($field-text)) = $field-text])">
在这段代码中 $ pos 是一个参数,包含您当前正在匹配的当前类别元素的位置,以及 $ field-text 是一个包含您要输出的文本的变量。
这是完整的XSLT样式表,它也应该为您提供所需的输出
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="record">
<add>
<doc>
<xsl:for-each select="category[. != '']">
<xsl:call-template name="split-cats">
<xsl:with-param name="prefix" select="''"/>
<xsl:with-param name="text" select="."/>
<xsl:with-param name="level" select="number(0)"/>
<!-- Position of the current category -->
<xsl:with-param name="pos" select="position()"/>
</xsl:call-template>
</xsl:for-each>
</doc>
</add>
</xsl:template>
<xsl:template name="split-cats">
<xsl:param name="text" select="."/>
<xsl:param name="prefix"/>
<xsl:param name="level" select="0"/>
<xsl:param name="pos"/>
<xsl:choose>
<xsl:when test="contains($text, '/')">
<xsl:variable name="field-text" select="concat($prefix, substring-before($text, '/'))"/>
<!-- Test no previous category begins with the text we are about to output -->
<xsl:if test="not(/record/category
[. != '']
[position() < $pos]
[substring(., 1, string-length($field-text)) = $field-text])">
<field>
<xsl:attribute name="name">
<xsl:text>category_</xsl:text>
<xsl:value-of select="$level"/>
</xsl:attribute>
<xsl:value-of select="$field-text"/>
</field>
</xsl:if>
<xsl:call-template name="split-cats">
<xsl:with-param name="prefix" select="concat($prefix, concat(substring-before($text, '/'), '/'))"/>
<xsl:with-param name="text" select="substring-after($text, '/')"/>
<xsl:with-param name="level" select="$level + 1"/>
<xsl:with-param name="pos" select="$pos"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="field-text" select="concat($prefix, $text)"/>
<!-- Test no previous category begins with the text we are about to output -->
<xsl:if test="not(/record/category
[. != '']
[position() < $pos]
[substring(., 1, string-length($field-text)) = $field-text])">
<field>
<xsl:attribute name="name">
<xsl:text>category_</xsl:text>
<xsl:value-of select="$level"/>
</xsl:attribute>
<xsl:value-of select="$field-text"/>
</field>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:1)
没有扩展函数,这个样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="record">
<add>
<doc>
<xsl:apply-templates select="category[1]"/>
</doc>
</add>
</xsl:template>
<xsl:template match="category" name="category">
<xsl:param name="pOutput"/>
<xsl:param name="pPrefix"/>
<xsl:param name="pLevel" select="0"/>
<xsl:param name="pSequence" select="concat(.,'/')"/>
<xsl:choose>
<xsl:when test="$pSequence">
<xsl:variable name="vItem"
select="concat($pPrefix,
substring-before($pSequence,
'/'))"/>
<xsl:variable name="vOutput"
select="concat('|',$vItem,'|')"/>
<xsl:if test="not(contains($pOutput,$vOutput))">
<field name="category_{$pLevel}">
<xsl:value-of select="$vItem"/>
</field>
</xsl:if>
<xsl:call-template name="category">
<xsl:with-param name="pOutput"
select="concat($pOutput,$vOutput)"/>
<xsl:with-param name="pPrefix"
select="concat($vItem,'/')"/>
<xsl:with-param name="pLevel" select="$pLevel + 1"/>
<xsl:with-param name="pSequence"
select="substring-after($pSequence,'/')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="following-sibling::category[1]">
<xsl:with-param name="pOutput" select="$pOutput"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
输出:
<add>
<doc>
<field name="category_0">Sport</field>
<field name="category_1">Sport/Racket Sports</field>
<field name="category_2">Sport/Racket Sports/Tennis</field>
<field name="category_2">Sport/Racket Sports/Badminton</field>
</doc>
</add>