
[英]XSLT beginner: Group XML based on unique element value XSLT 1.0
[英]Use XSLT 1.0 to group XML elements into buckets, in order, based on some criteria
说我有一些我想要转换为HTML的XML。 XML分为有序部分:
<?xml version="1.0" encoding="utf-8"?>
<root>
<section attr="someCriteria">
<h1>Title 1</h1>
<p>paragraph 1-1</p>
<p>paragraph 1-2</p>
</section>
<section attr="someOtherCriteria">
<h3>Subtitle 2</h3>
<ul>
<li>list item 2-1</li>
<li>list item 2-2</li>
<li>list item 2-3</li>
<li>list item 2-4</li>
</ul>
</section>
<section attr="anotherSetOfCriteria">
<warning>
Warning: This product could kill you
</warning>
</section>
<section attr="evenMoreCriteria">
<disclaimer>
You were warned
</disclaimer>
</section>
<section attr="criteriaSupreme">
<p>Copyright 1999-2011</p>
</section>
</root>
我有几个这样的XML文档。 我需要根据标准对这些部分进行分组和转换。 将有两种不同的桶。
<div class="FormatOne"></div>
) <div class="FormatTwo"></div>
),则会创建一个新存储桶,并将部分内容放在此存储桶中 因此,对于每个文档,根据分离存储桶的逻辑,文档可能最终如下:
<body>
<div class="FormatOne">
<h1>Title 1</h1>
<p>paragraph 1-1</p>
<p>paragraph 1-2</p>
<h3>Subtitle 2</h3>
<ul>
<li>list item 2-1</li>
<li>list item 2-2</li>
<li>list item 2-3</li>
<li>list item 2-4</li>
</ul>
</div>
<div class="FormatTwo">
<span class="warningText">
Warning: This product could kill you
</span>
</div>
<div class="FormatOne">
<span class="disclaimerText"> You were warned</span>
<p class="copyright">Copyright 1999-2011</p>
</div>
</body>
这个:
<body>
<div class="FormatOne">
<h1>Title 1</h1>
<p>paragraph 1-1</p>
<p>paragraph 1-2</p>
<h3>Subtitle 2</h3>
</div>
<div class="FormatTwo">
<ul>
<li>list item 2-1</li>
<li>list item 2-2</li>
<li>list item 2-3</li>
<li>list item 2-4</li>
</ul>
</div>
<div class="FormatOne">
<span class="warningText">
Warning: This product could kill you
</span>
<span class="disclaimerText"> You were warned</span>
<p class="copyright">Copyright 1999-2011</p>
</div>
</body>
甚至这个:
<body>
<div class="FormatOne">
<h1>Title 1</h1>
<p>paragraph 1-1</p>
<p>paragraph 1-2</p>
<h3>Subtitle 2</h3>
<ul>
<li>list item 2-1</li>
<li>list item 2-2</li>
<li>list item 2-3</li>
<li>list item 2-4</li>
</ul>
<span class="warningText">
Warning: This product could kill you
</span>
<span class="disclaimerText"> You were warned</span>
<p class="copyright">Copyright 1999-2011</p>
</div>
</body>
取决于部分的定义方式。
有没有办法使用XSLT来执行这种类型的分组魔术?
任何帮助都会很棒。 谢谢!
我想出了一个解决方案,涉及顺序击中每个部分。 每个部分的处理分为两部分:“shell”和“contents”部分。 “shell”负责呈现<div class="FormatOne">...</div>
位,“内容”负责呈现当前部分和所有后续部分的实际内容, 直到非找到匹配部分 。
找到不匹配的部分后,控制将恢复为该部分的“shell”模板。
这提供了一些有趣的灵活性:“shell”模板在它们匹配的内容中可能非常激进,而“内容”部分可能更具辨别力。 具体来说,使用第一个示例输出,您需要使用warning
元素显示为<span class="warningText">...</span>
,这是通过更紧密匹配的模板完成的。
所有“内容”模板在呈现其当前部分的内容之后,调用命名模板来查找“下一个”适当的内容部分。 这有助于合并规则以确定哪些资格为“匹配”部分。
这是我的代码,用于复制您在第一个示例中要求的内容:
<?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" />
<xsl:template match="/">
<body>
<xsl:apply-templates select="/root/section[1]" mode="shell" />
</body>
</xsl:template>
<xsl:template match="section[
@attr = 'someCriteria' or
@attr = 'someOtherCriteria' or
@attr = 'evenMoreCriteria' or
@attr = 'criteriaSupreme']" mode="shell">
<div class="FormatOne">
<xsl:apply-templates select="." mode="contents" />
</div>
<xsl:apply-templates select="following-sibling::section[
@attr != 'someCritera' and
@attr != 'someOtherCriteria' and
@attr != 'evenMoreCriteria' and
@attr != 'criteriaSupreme'][1]" mode="shell" />
</xsl:template>
<xsl:template name="nextFormatOne">
<xsl:variable name="next" select="following-sibling::section[1]" />
<xsl:if test="$next[
@attr = 'someCriteria' or
@attr = 'someOtherCriteria' or
@attr = 'evenMoreCriteria' or
@attr = 'criteriaSupreme']">
<xsl:apply-templates select="$next" mode="contents" />
</xsl:if>
</xsl:template>
<xsl:template match="section[
@attr = 'someCriteria' or
@attr = 'someOtherCriteria']" mode="contents">
<xsl:copy-of select="*" />
<xsl:call-template name="nextFormatOne" />
</xsl:template>
<xsl:template match="section[@attr = 'evenMoreCriteria']" mode="contents">
<span class="disclaimerText">
<xsl:value-of select="disclaimer" />
</span>
<xsl:call-template name="nextFormatOne" />
</xsl:template>
<xsl:template match="section[@attr = 'criteriaSupreme']" mode="contents">
<p class="copyright">
<xsl:value-of select="p" />
</p>
<xsl:call-template name="nextFormatOne" />
</xsl:template>
<xsl:template match="section[@attr = 'anotherSetOfCriteria']" mode="shell">
<div class="FormatTwo">
<xsl:apply-templates select="." mode="contents" />
</div>
<xsl:apply-templates select="
following-sibling::section[@attr != 'anotherSetOfCriteria'][1]"
mode="shell" />
</xsl:template>
<xsl:template name="nextFormatTwo">
<xsl:variable name="next" select="following-sibling::section[1]" />
<xsl:if test="$next[@attr = 'anotherSetOfCriteria']">
<xsl:apply-templates select="$next" mode="contents" />
</xsl:if>
</xsl:template>
<xsl:template
match="section[@attr = 'anotherSetOfCriteria']"
mode="contents">
<span class="warningText">
<xsl:value-of select="warning" />
</span>
<xsl:call-template name="nextFormatTwo" />
</xsl:template>
</xsl:stylesheet>
“如果格式相同,则每个部分将与上一部分进入同一个存储区。如果不是,则创建一个新存储桶。”
您所描述的内容基本上是指令执行的任务
<xsl:for-each-group group-adjacent="....">
在XSLT 2.0中。 这假设您可以编写一个将“条件”转换为bucket-name的函数,并在group-adjacent属性中调用此函数。
那么,您需要使用XSLT 1.0的约束有多难?
如果你坚持使用1.0,那么你将不得不采用Chris Nielsen提出的兄弟递归设计模式。
查看template
, if
, choose
和for-each
:
这些(以及其他XSLT元素)将允许您进行条件行为以在不同的转换逻辑之间切换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.