我是XSLT的新手,所以我要求帮助。我有许多XML文档,其中以下是一个代表性示例。文档分为<sub-doc(n)>
个元素,这些元素进一步划分为<section>
个元素。这些部分中包含ZERO或更多<heading>
元素以及一个或多个<paragraph>
元素。我的目标是确保每个部分最多只有一个<heading>
元素,将具有多个标题的部分划分为多个部分,每个部分中包含一个标题。完成此操作后,紧随<paragraph>
之后的<heading>
元素必须与<heading>
一起放入新<section>
。例如,请注意,在以下示例中,<section>
的第一个<sub-doc1>
有两个<heading>
元素。我需要将此<section>
元素拆分为两个<section>
元素,每个元素都有自己的<heading>
和后续<paragraph>
元素。
<document>
<sub-doc1>
<section> <!-- This section needs to be split -->
<heading>Subdoc1 first heading text</heading>
<paragraph>A lot of text</paragraph>
<paragraph>Yet more text</paragraph>
<paragraph>More text</paragraph>
...
<heading>Subdoc1 second heading text</heading>
<paragraph>Even more text</paragraph>
<paragraph>Some text</paragraph>
...
</section>
<section>
<paragraph>Even more text</paragraph>
...
</section>
</sub-doc1>
<sub-doc2>
<section>
<heading>Subdoc2, first heading text</heading>
<paragraph>A lot of text here</paragraph>
<paragraph>Yet more text here</paragraph>
<paragraph>Yet more text here</paragraph>
...
</section>
</sub-doc2>
</document>
也就是说,转换后的文档需要如下所示:
<document>
<sub-doc1>
<section> <!-- This section got split into two sections -->
<heading>Subdoc1 first heading text</heading>
<paragraph>A lot of text</paragraph>
<paragraph>Yet more text</paragraph>
<paragraph>More text</paragraph>
...
</section>
<section> <!-- This is a new section -->
<heading>Subdoc1 second heading text</heading>
<paragraph>Even more text</paragraph>
<paragraph>Some text</paragraph>
...
</section>
<section>
<paragraph>Even more text</paragraph>
...
</section>
</sub-doc1>
<sub-doc2>
<section>
<heading>Subdoc2, first heading text</heading>
<paragraph>A lot of text here</paragraph>
<paragraph>Yet more text here</paragraph>
<paragraph>Yet more text here</paragraph>
...
</section>
</sub-doc2>
</document>
请注意,某些部分根本没有<heading>
个元素。在这些情况下,这些部分应保持不变。此外,某些部分只有一个<heading>
。这些部分也应保持不变。文档中的其他内容应保持不变。唯一需要进行的转换是在文档中任何位置<section>
具有多个<heading>
的情况下。
同样,我是XSLT的新手,无法理解完成任务的XSL。谢谢你的帮助。
答案 0 :(得分:0)
这个样式表就像你问的那样。它使用键来选择与给定标题相对应的所有paragraph
元素。
我显示的输出对应于删除了省略号的样本输入。
请注意,此解决方案需要全部
包含任何section
元素的heading
元素都有heading
个元素作为第一个子元素。即在第一个paragraph
之前没有heading
个元素。
如果这个假设是错误的,那么样式表将需要一个小的改变。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="paragraph-for-heading" match="paragraph" use="generate-id(preceding-sibling::heading[1])"/>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="section[heading]">
<xsl:apply-templates select="heading"/>
</xsl:template>
<xsl:template match="heading">
<section>
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
<xsl:apply-templates select="key('paragraph-for-heading', generate-id())"/>
</section>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
<document>
<sub-doc1>
<section>
<heading>Subdoc1 first heading text</heading>
<paragraph>A lot of text</paragraph>
<paragraph>Yet more text</paragraph>
<paragraph>More text</paragraph>
</section>
<section>
<heading>Subdoc1 second heading text</heading>
<paragraph>Even more text</paragraph>
<paragraph>Some text</paragraph>
</section>
<section>
<paragraph>Even more text</paragraph>
</section>
</sub-doc1>
<sub-doc2>
<section>
<heading>Subdoc2, first heading text</heading>
<paragraph>A lot of text here</paragraph>
<paragraph>Yet more text here</paragraph>
<paragraph>Yet more text here</paragraph>
</section>
</sub-doc2>
</document>
答案 1 :(得分:-1)
我能够生成您正在寻找的输出。对我来说,这种类型的处理需要在XPath中使用前导兄弟来抓取我正在寻找的组元素,当它们存在于另一组元素之间时。
由于你还有一些没有标题的部分,我不得不以不同的方式处理这些部分。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="document">
<document>
<!-- Select the sub-doc elements and print their names, then process their children -->
<xsl:for-each select="*">
<xsl:element name="{local-name(.)}">
<xsl:for-each select="section">
<!-- For a section with 1 or more headings -->
<xsl:choose>
<xsl:when test="count(heading) > 0">
<!-- Print each section, heading and the paragraphs that follow -->
<xsl:for-each select="heading">
<xsl:variable name="currentHeading" select="current()"/>
<section>
<heading>
<xsl:value-of select="."/>
</heading>
<!-- Pick paragraphs that follow current heading -->
<xsl:variable name="paragraphList" select="../paragraph[preceding-sibling::heading[1] = $currentHeading]"/>
<xsl:for-each select="$paragraphList">
<paragraph>
<xsl:value-of select="."/>
</paragraph>
</xsl:for-each>
</section>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<section>
<xsl:for-each select="paragraph">
<paragraph>
<xsl:value-of select="."/>
</paragraph>
</xsl:for-each>
</section>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</document>
</xsl:template>
</xsl:stylesheet>
尼拉吉