如何制作XSLT来改变它:
<root>
<element>This
<element>is</element>
</element>
<element>normal!</element>
<element>This</element>
<element>will
<special>break here</special>
<element>and
<element>also
<special>here!</special>
</element>
</element>
</element>
</root>
进入这个:
<root>
<content>This is normal! This will</content>
<special>break here</special>
<content>and also</content>
<special>here!</special>
</root>
考虑<special>
可以出现任意次数。我想我需要处理文件两次才能做到这一点,但我需要立即完成。
编辑:只是一个澄清,它不是一个简单的副本,内容也从一端转换到另一端(这就是为什么我认为我需要两种不同的转换)。
EDIT2 :这是我想要的算法:
1)继续处理所有元素,直到找到一些特殊元素,将其全部放到<content>
2)如果下一个元素是特殊的,则将其放在<specialContent>
3)如果还有什么,请转到第1步。
EDIT3 我更改了我的示例xml以使其更清晰。
答案 0 :(得分:2)
目前所有现有答案似乎都在这个XML文档上发现了:
<root>
<element>This
<element>is</element></element>
<element>normal!</element>
<element>This</element>
<element>will
<special>break here</special>
<element>and
<element>also
<special>here!</special>
</element>
</element>
<element>But not here</element>
</element>
</root>
这是一个正确处理它的转换:
<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="content" match="element"
use="generate-id((ancestor::special|preceding::special)[last()])"/>
<xsl:template match="/*">
<xsl:copy>
<content>
<xsl:apply-templates select="key('content', '')"/>
</content>
<xsl:apply-templates select="//special" />
</xsl:copy>
</xsl:template>
<xsl:template match="special">
<xsl:copy-of select="." />
<content>
<xsl:apply-templates select=
"key('content', generate-id())" />
</content>
</xsl:template>
<xsl:template match="element">
<xsl:value-of select="normalize-space(text())" />
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
在上面的XML文档中应用时,会生成所需的正确结果:
<root>
<content>This is normal! This will </content>
<special>break here</special>
<content>and also </content>
<special>here!</special>
<content>But not here </content>
</root>
答案 1 :(得分:0)
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="content//*[not(self::SpecialContent)]">
<xsl:apply-templates/>
</xsl:template>
应该足够了。
答案 2 :(得分:0)
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="root">
<content>
<xsl:copy-of select=".//content/text()[following-sibling::node()[1][self::subcontent]]" />
<xsl:copy-of select=".//subcontent/text()[following-sibling::node()[1][self::subsubcontent]]" />
<xsl:copy-of select=".//subsubcontent/text()[following-sibling::node()[1][self::SpecialContent]]" />
</content>
<xsl:for-each select=".//SpecialContent">
<xsl:copy-of select="." />
</xsl:for-each>
<content>
<xsl:copy-of select=".//subsubcontent/text()[preceding-sibling::node()[1][self::SpecialContent]]" />
<xsl:copy-of select=".//subcontent/text()[preceding-sibling::node()[1][self::subsubcontent]]" />
<xsl:copy-of select=".//content/text()[preceding-sibling::node()[1][self::subcontent]]" />
</content>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
不是很漂亮,但如果有的话,应该使用其他转换
答案 3 :(得分:0)
我认为您可以实现此目的的一种方法是将所有元素*元素按第一个**特殊元素分组,该元素是后代或后续元素,
<xsl:key name="content"
match="element"
use="generate-id((descendant::special|following::special)[1])" />
然后,您可以通过匹配文档
中的所有 speical 元素开始 <xsl:apply-templates select="//special" />
对于每个匹配的特殊元素,您可以将所有关联的元素元素组合在一起,这些元素将此当前元素作为其第一个后代或后续元素。< / p>
<content>
<xsl:apply-templates select="key('content', generate-id())" />
</content>
因此,给出以下XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="content"
match="element"
use="generate-id((descendant::special|following::special)[1])" />
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="//special" />
</xsl:copy>
</xsl:template>
<xsl:template match="special">
<content>
<xsl:apply-templates select="key('content', generate-id())" />
</content>
<xsl:copy-of select="." />
</xsl:template>
<xsl:template match="element">
<xsl:value-of select="normalize-space(text())" /><xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
当应用于您的示例XML时,输出以下内容
<root>
<content>This is normal! This will </content>
<special>break here</special>
<content>and also </content>
<special>here!</special>
</root>
(请注意,每个内容标记的末尾都有一个空格,但如果需要,我可以轻松调整XSLT以删除它。)
答案 4 :(得分:0)
Dimitri的回答非常好,但由于生成的内容和非常深的模板层次结构,它会破坏我的XSLT中的某些东西。
以下是我最终使用的解决方案:
首先,我进行所有正常处理,然后调用后期处理:
<xsl:variable name="content">
<xsl:apply-templates />
</xsl:variable>
<xsl:apply-templates select="msxsl:node-set($content)" mode="postProcess" />
在后期处理中,它会在其类属性中搜索任何不是div
具有WideContent标记的内容,并将相邻的兄弟分组放在另一个div中,具有WideContent标记的那些只是被复制(但可以作为同样也是小组)。
<xsl:template match="/*[not(self::xhtml:div[contains(@class,'WideContent')])][preceding-sibling::*[1][self::xhtml:div[contains(@class,'WideContent')]] or position()=1]" mode="postProcess">
<div class="NormalContent">
<xsl:call-template name="postProcessNormalContent" />
</div>
</xsl:template>
<xsl:template name="postProcessNormalContent" match="/*[not(self::xhtml:div[contains(@class,'WideContent')])]" mode="postProcessNormalContent">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::*[1]" mode="postProcessNormalContent" />
</xsl:template>
<xsl:template match="xhtml:div[contains(@class,'WideContent')]" mode="postProcess">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="node()" mode="postProcess" />
<xsl:template match="node()" mode="postProcessNormalContent" />
任何关于如何改进的建议都会很乐意。