【发布时间】:2010-10-18 18:25:27
【问题描述】:
我有一些带有<ListItem> 元素的XML,我想用<List> 元素包装任何连续运行。因此,源 XML 看起来像这样:
<Section>
<Head>Heading</Head>
<Para>Blah</Para>
<ListItem>item 1</ListItem>
<ListItem>item 2</ListItem>
<ListItem>item 3</ListItem>
<ListItem>item 4</ListItem>
<Para>Something else</Para>
</Section>
我想把它转换成这样的:
<Section>
<Head>Heading</Head>
<Para>Blah</Para>
<List>
<ListItem>item 1</ListItem>
<ListItem>item 2</ListItem>
<ListItem>item 3</ListItem>
<ListItem>item 4</ListItem>
</List>
<Para>Something else</Para>
</Section>
使用 XSLT。我确定这很明显,但我不能在晚上的这个时候解决它。谢谢!
编辑:大多数人可以放心地忽略这一点。
这个 XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
<Story>
<Section id="preface">
<ChapterTitle>Redacted</ChapterTitle>
<HeadA>Redacted</HeadA>
<Body>Redacted</Body>
<BulletListItem>Item1</BulletListItem>
<BulletListItem>Item2</BulletListItem>
<BulletListItem>Item3</BulletListItem>
<BulletListItem>Item4</BulletListItem>
<HeadA>Redacted</HeadA>
<Body>Redacted</Body>
<HeadA>Redacted</HeadA>
<Body>Redacted</Body>
<Body>Redacted<Italic>REDACTED</Italic>Redacted</Body>
<BulletListItem>Second list Item1</BulletListItem>
<BulletListItem>Second list Item2</BulletListItem>
<BulletListItem>Second list Item3</BulletListItem>
<BulletListItem>Second list Item4</BulletListItem>
<Body>Redacted</Body>
</Section>
</Story>
</Root>
有了这个 XSL:
<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="kFollowing" match="BulletListItem[preceding-sibling::*[1][self::BulletListItem]]"
use="generate-id(preceding-sibling::BulletListItem
[not(preceding-sibling::*[1][self::BulletListItem])])"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BulletListItem
[not(preceding-sibling::*[1][self::BulletListItem])]">
<BulletList>
<xsl:call-template name="identity"/>
<xsl:apply-templates mode="copy" select="key('kFollowing', generate-id())"/>
</BulletList>
</xsl:template>
<xsl:template match="BulletListItem[preceding-sibling::*[1][self::BulletListItem]]"/>
<xsl:template match="BulletListItem" mode="copy">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
当使用 Ruby REXML 和 XML/XSLT 处理时,会生成此 XML(输出漂亮打印):
<Root>
<Story>
<Section id='preface'>
<ChapterTitle>
Redacted
</ChapterTitle>
<HeadA>
Redacted
</HeadA>
<Body>
Redacted
</Body>
<BulletList>
<BulletListItem>
Item1
</BulletListItem>
<BulletListItem>
Item2
</BulletListItem>
<BulletListItem>
Item3
</BulletListItem>
<BulletListItem>
Item4
</BulletListItem>
<BulletListItem>
Second list Item2
</BulletListItem>
<BulletListItem>
Second list Item3
</BulletListItem>
<BulletListItem>
Second list Item4
</BulletListItem>
</BulletList>
<HeadA>
Redacted
</HeadA>
<Body>
Redacted
</Body>
<HeadA>
Redacted
</HeadA>
<Body>
Redacted
</Body>
<Body>
Redacted
<Italic>
REDACTED
</Italic>
Redacted
</Body>
<BulletList>
<BulletListItem>
Second list Item1
</BulletListItem>
</BulletList>
<Body>
Redacted
</Body>
</Section>
</Story>
</Root>
您会看到两个列表卡在一起,中间的部分丢失了。不确定这是 Ruby 库还是 XSLT 中的错误。
【问题讨论】:
-
我懒得搜索重复...如果有人发布链接,我会删除答案。
-
好问题,+1。请参阅我的答案,了解基于密钥的高效解决方案。
-
我收回我所说的很明显:P 我真的需要正确学习 XSLT ...