如何使用 XSLT 包装一组相邻元素? [英] How can I wrap a group of adjacent elements using XSLT?
问题描述
我有一些带有
元素的 XML,我想用
元素包装任何连续运行.所以,源 XML 看起来像这样:
I have some XML with <ListItem>
elements, and I'd like to wrap any consecutive runs with <List>
elements. So, source XML would look something like this:
<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.我确定这很明显,但我在晚上的这个时候无法解决.谢谢!
using XSLT. I'm sure it's obvious but I can't work it out at this time in the evening. Thanks!
大多数人可以安全地忽略这一点.
this can be safely ignored by most people.
这个 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(输出漂亮打印):
When processed with Ruby REXML and XML/XSLT produces this XML (output prettyprint):
<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 中的错误.
You'll see that the two lists get jammed together and the bit in between gets lost. Not sure if this is a bug in the Ruby libraries or in your XSLT.
推荐答案
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="@*|node()[1]"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="ListItem">
<List>
<xsl:call-template name="ListItem"/>
</List>
<xsl:apply-templates select="following-sibling::node()
[not(self::ListItem)][1]"/>
</xsl:template>
<xsl:template match="ListItem[preceding-sibling::node()[1]
/self::ListItem]"
name="ListItem">
<xsl:copy>
<xsl:apply-templates select="@*|node()[1]"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]
/self::ListItem"/>
</xsl:template>
</xsl:stylesheet>
输出:
<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>
编辑 3:使用 strip-space
表示它是什么.
Edit 3: Using strip-space
for what it is.
这篇关于如何使用 XSLT 包装一组相邻元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!