我必须构建一个XSLT样式表来转换像这样的xml:
<message>
<line/>
<silence/>
<dot/><line/><line/>
<silence/>
<dot/>
<silence/>
<line/><dot/><dot/><dot/>
</message>
这样的事情:
<complexMessage>
<word code="-"/>
<word code=".--"/>
<word code="."/>
<word code="-..."/>
</complexMessage>
(注意word
元素之后每个silence
元素的关闭方式
我怎么能这样做?
答案 0 :(得分:3)
这个解决方案都是:由于使用了密钥,因此更短,更重要的是,效率更高:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kPhraseByMorse"
match="*[not(self::silence) and not(self::message)]"
use="generate-id(preceding-sibling::silence[1])"/>
<xsl:template match="/">
<complexMessage>
<word>
<xsl:call-template name="makeCode"/>
</word>
<xsl:apply-templates select="*/silence"/>
</complexMessage>
</xsl:template>
<xsl:template match="silence">
<word>
<xsl:call-template name="makeCode">
<xsl:with-param name="pId" select="generate-id()"/>
</xsl:call-template>
</word>
</xsl:template>
<xsl:template name="makeCode">
<xsl:param name="pId"/>
<xsl:attribute name="code">
<xsl:apply-templates select="key('kPhraseByMorse', $pId)"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="dot">.</xsl:template>
<xsl:template match="line">-</xsl:template>
</xsl:stylesheet>
在提供的源XML上应用此转换时,会生成正确的结果:
<complexMessage>
<word code="-"/>
<word code=".--"/>
<word code="."/>
<word code="-..."/>
</complexMessage>
答案 1 :(得分:2)
我相信这可以实现您的目标:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="firstSilenceID" select="generate-id(//silence[1])" />
<xsl:template match="/">
<complexMessage>
<xsl:apply-templates select="/message//silence"/>
</complexMessage>
</xsl:template>
<xsl:template name="message">
</xsl:template>
<xsl:template match="silence" >
<!--If this is the first <silince> element, generate words for everything before it -->
<xsl:if test="$firstSilenceID = generate-id(current())">
<xsl:call-template name="complexMessage">
<xsl:with-param name="word" select="preceding-sibling::*"/>
</xsl:call-template>
</xsl:if>
<!--Generate words for everything after THIS <silence> element -->
<xsl:call-template name="complexMessage">
<xsl:with-param name="word" select="following-sibling::*[generate-id(preceding-sibling::silence[1]) = generate-id(current())]"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="complexMessage">
<xsl:param name="word"/>
<word>
<xsl:attribute name="code">
<xsl:apply-templates select="$word" />
</xsl:attribute>
</word>
</xsl:template>
<xsl:template match="dot">
<xsl:text>.</xsl:text>
</xsl:template>
<xsl:template match="line">
<xsl:text>-</xsl:text>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:1)
怎么样:
<?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"/>
<xsl:template match="/message">
<complexMessage>
<xsl:apply-templates select="*[1]"/>
</complexMessage>
</xsl:template>
<xsl:template match="line" mode="value">-</xsl:template>
<xsl:template match="dot" mode="value">.</xsl:template>
<xsl:template match="silence" mode="value"/>
<xsl:template match="silence" name="write">
<xsl:param name="prev" select="''"/>
<word code="{$prev}"/>
<xsl:apply-templates select="following-sibling::*[1]"/>
</xsl:template>
<xsl:template match="line | dot">
<xsl:param name="prev" select="''"/>
<xsl:variable name="value"><xsl:apply-templates select="." mode="value"/></xsl:variable>
<xsl:choose>
<xsl:when test="following-sibling::*">
<xsl:apply-templates select="following-sibling::*[1]">
<xsl:with-param name="prev" select="concat($prev,$value)"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="write">
<xsl:with-param name="prev" select="concat($prev,$value)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
对于大型文档,它可能会触发无限递归检测 - 在这种情况下,我会尝试查看涉及<xsl:apply-templates select="*[1] | silence"/>
的内容,并且在每种情况下只会前进到下一次静默或EOF(如果你看到的话)我的意思是说)。如果您想要重构版本来表明这一点,请告诉我......