HI
我的XML文档具有以下布局
<root>
<child>
<item type="ID">id1</item>
<item type="TEXT">text1</item>
</child>
<child>
<item type="ID"/>
<item type="TEXT">text2</item>
</child>
<child>
<item type="ID"/>
<item type="TEXT">text3</item>
</child>
<child>
<item type="ID">id2</item>
<item type="TEXT">text4</item>
</child>
<child>
<item type="ID"/>
<item type="TEXT">text5</item>
</child>
...
</root>
每次有一个带有type = ID的空项标签时,就意味着它与前一个兄弟有相同的值。现在我想将其转换为
<root>
<child id="id1">text1text2text3</child>
<child id="id2">text4text5</child>
...
</root>
我的解决方法是
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<root>
<xsl:apply-templates select="//child/item[@type='ID'][text()='id1' or text()='id2']"/>
</root>
</xsl:template>
<xsl:template match="child/item[text()='id1' or text()='id2']">
<child id="{text()}">
<xsl:value-of select="./../item[@type='TEXT']/."/>
<xsl:apply-templates select="./../following::*[1]/item[@type='ID'][not(text()='id1' or text()='id2')]"/>
</child>
</xsl:template>
<xsl:template match="child/item[not(text()='id1' or text()='id2')]">
<xsl:value-of select="./../item[@type='TEXT']/."/>
<xsl:apply-templates select="./../following::*[1]/item[@type='ID'][not(text()='id1' or text()='id2')]"/>
</xsl:template>
</xsl:stylesheet>
它有效,但是丑陋且不灵活。例如,如果我有任意id值,而不仅仅是id1和id2。有没有人有好的建议或更好的解决方案?
答案 0 :(得分:1)
这个XSLT 1.0样式表应该这样做:
<?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="/*">
<root>
<!-- visit each "child" element with a non-blank ID -->
<xsl:for-each select="child[item[@type='ID'] != '']">
<xsl:variable name="this-id" select="item[@type='ID']"></xsl:variable>
<child id="{$this-id}">
<!-- visit this node and each following "child" element which
1. has a blank ID, and
2. whose immediate preceding non-blank ID child element is this one -->
<xsl:for-each select=".|following-sibling::child
[item[@type='ID'] = '']
[preceding-sibling::child[item[@type='ID'] != ''][1]/item[@type='ID']=$this-id]">
<xsl:value-of select="item[@type='TEXT']"/>
</xsl:for-each>
</child>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
XSLT 2.0解决方案:
<xsl:template match="root">
<xsl:for-each-group select="child"
group-starting-with="child[string(item[@type='ID'])]">
<child id="{item[@type='ID']}">
<xsl:value-of select="current-group()/item[@type='TEXT']" separator=""/>
</child>
</xsl:for-each-group>
</xsl:template>
答案 2 :(得分:1)
此XSLT 1.0转换:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kFollowing" match="item[@type='TEXT']"
use="((..|../preceding-sibling::child)
/item[@type='ID'and string(.)]
)[last()]"/>
<xsl:template match="/*">
<root>
<xsl:apply-templates select=
"*[item[@type='ID' and string(.)]]"/>
</root>
</xsl:template>
<xsl:template match="*">
<child id="{item[@type='ID']}">
<xsl:copy-of select="key('kFollowing', item[@type='ID'])/text()"/>
</child>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<root>
<child>
<item type="ID">id1</item>
<item type="TEXT">text1</item>
</child>
<child>
<item type="ID"/>
<item type="TEXT">text2</item>
</child>
<child>
<item type="ID"/>
<item type="TEXT">text3</item>
</child>
<child>
<item type="ID">id2</item>
<item type="TEXT">text4</item>
</child>
<child>
<item type="ID"/>
<item type="TEXT">text5</item>
</child> ...
</root>
生成想要的正确结果:
<root>
<child id="id1">text1text2text3</child>
<child id="id2">text4text5</child>
</root>
解释:使用键表示所有匹配的item
元素与前一个item
与@type='ID'
和子文本节点之间的关系。< / p>