我正在处理一些具有扁平结构的XML,其中通过重复的元素组隐式识别项目,而没有正确地嵌套在每个项目的单个父元素中(这是导致头痛的原因)。我需要使用XSLT将它转换为相同的版本,其中某些组使用不同的文本输出,具体取决于兄弟元素组中其中一个元素的值。所以,如果输入看起来像这样:
<items>
<item_title>Item 1</item_title>
<text1>Item 1 Text 1</text1>
<text2>Item 1 Text 2</text2>
<text3>Item 1 Text 3</text3>
<text4>Item 1 Text 4</text4>
<text5>Item 1 Text 5</text5>
<item_title>Item 2</item_title>
<text1>Item 2 Text 1</text1>
<flag>Suppress text</flag>
<text4>Item 2 Text 4</text4>
<text5>Item 2 Text 5</text5>
<item_title>Item 3</item_title>
<text1>Item 3 Text 1</text1>
<text3>Item 3 Text 3</text3>
<text4>Item 3 Text 4</text4>
<item_title>Item 4</item_title>
<text1>Item 4 Text 1</text1>
<text4>Item 4 Text 4</text4>
<text5>Item 4 Text 5</text5>
<item_title>Item 5</item_title>
<text2>Item 5 Text 2</text2>
<text3>Item 5 Text 3</text3>
<flag>Suppress text</flag>
<text5>Item 5 Text 5</text5>
</items>
我想输出这样的东西:
<items>
<item_title>Item 1</item_title>
<text1>Item 1 Text 1</text1>
<text2>Item 1 Text 2</text2>
<text3>Item 1 Text 3</text3>
<text4>Item 1 Text 4</text4>
<text5>Item 1 Text 5</text5>
<item_title>Item 2</item_title>
<text1>The text of this item has been suppressed.</text1>
<item_title>Item 3</item_title>
<text1>Item 3 Text 1</text1>
<text3>Item 3 Text 3</text3>
<text4>Item 3 Text 4</text4>
<item_title>Item 4</item_title>
<text1>Item 4 Text 1</text1>
<text4>Item 4 Text 4</text4>
<text5>Item 4 Text 5</text5>
<item_title>Item 5</item_title>
<text1>The text of this item has been suppressed.</text1>
</items>
我一直在困惑如何(实际上,是否)可以编写一个XPath表达式,为每个/ item_title标识它是否具有follow-sibling :: flag之前(按文档顺序)接下来是下一个-sibling :: item_title,然后对于每个文本元素,我可以将这个XPath表达式嵌入到一个XPath表达式中,该表达式标识元素的最接近的前一个兄弟:: item_title是否符合这个条件(在这种情况下元素不会得到输出) )。但我无法弄清楚如何。
这是通过我提到的方法,还是通过某种替代方法实现的?
这是一个问题,因为我正在处理垃圾XML,但这就是我所拥有的。
感谢您的任何建议。
答案 0 :(得分:1)
如果您使用
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="title" match="items/*[not(self::item_title)]" use="generate-id(preceding-sibling::item_title[1])"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="items">
<xsl:copy>
<xsl:apply-templates select="item_title"/>
</xsl:copy>
</xsl:template>
<xsl:template match="items/item_title[key('title', generate-id())[self::flag[. = 'Suppress text']]]">
<item title="{.}">
<item1>The text of this item has been suppressed.</item1>
</item>
</xsl:template>
<xsl:template match="items/item_title[not(key('title', generate-id())[self::flag[. = 'Suppress text']])]">
<item title="{.}">
<xsl:apply-templates select="key('title', generate-id())"/>
</item>
</xsl:template>
</xsl:stylesheet>
你得到了
<items>
<item title="Item 1">
<text1>Item 1 Text 1</text1>
<text2>Item 1 Text 2</text2>
<text3>Item 1 Text 3</text3>
<text4>Item 1 Text 4</text4>
<text5>Item 1 Text 5</text5>
</item>
<item title="Item 2">
<item1>The text of this item has been suppressed.</item1>
</item>
<item title="Item 3">
<text1>Item 3 Text 1</text1>
<text3>Item 3 Text 3</text3>
<text4>Item 3 Text 4</text4>
</item>
<item title="Item 4">
<text1>Item 4 Text 1</text1>
<text4>Item 4 Text 4</text4>
<text5>Item 4 Text 5</text5>
</item>
<item title="Item 5">
<item1>The text of this item has been suppressed.</item1>
</item>
</items>
如果您不想更正嵌套,请使用
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="title" match="items/*[not(self::item_title)]" use="generate-id(preceding-sibling::item_title[1])"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="items">
<xsl:copy>
<xsl:apply-templates select="item_title"/>
</xsl:copy>
</xsl:template>
<xsl:template match="items/item_title[key('title', generate-id())[self::flag[. = 'Suppress text']]]">
<xsl:copy-of select="."/>
<item1>The text of this item has been suppressed.</item1>
</xsl:template>
<xsl:template match="items/item_title[not(key('title', generate-id())[self::flag[. = 'Suppress text']])]">
<xsl:copy-of select="."/>
<xsl:apply-templates select="key('title', generate-id())"/>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
我一直在困惑如何(实际上,是否)可以编写一个XPath表达式,为每个/ item_title标识它是否具有follow-sibling :: flag之前(按文档顺序) next following-sibling :: item_title
Martin建议使用密钥作为一个整体来解决问题的更好方法,但是为了参考,可以通过汇总文档中所有以下兄弟flag
和item_title
元素的列表来完成此特定测试订购,然后看看第一个是否是一个标志:
<xsl:template match="item_title[
(following-sibling::item_title | following-sibling::flag)[1][self::flag]]">