【发布时间】:2015-01-03 17:02:55
【问题描述】:
这里有许多扁平化的问题,但没有一个涉及这种复杂程度。
我有一个看起来像这样的 xml 文档:
<document>
<div class='target-one'>
maybe some text node, maybe not...1
<randomElement>
maybe some text node, maybe not...2
</randomElement>
<div class='target-one'>
<randomElement>
maybe some text node, maybe not...3
</randomElement>
</div>
maybe some text node, maybe not...4
<randomElement>
maybe some text node, maybe not...5
</randomElement>
<div class='target-two'>
maybe some text node, maybe not...6
<randomElement>
maybe some text node, maybe not...7
</randomElement>
</div>
maybe some text node, maybe not...8
<randomElement>
maybe some text node, maybe not...9
</randomElement>
</div>
<div class='target-two'>
maybe some text node, maybe not...10
<randomElement>
maybe some text node, maybe not...11
</randomElement>
<div class='target-one'>
<randomElement>
maybe some text node, maybe not...12
</randomElement>
</div>
maybe some text node, maybe not...13
<randomElement>
maybe some text node, maybe not...14
</randomElement>
<div class='target-two'>
maybe some text node, maybe not...15
<randomElement>
maybe some text node, maybe not...16
</randomElement>
</div>
maybe some text node, maybe not...17
<randomElement>
maybe some text node, maybe not...18
</randomElement>
</div>
</document>
所以有一个可以按任意顺序嵌套的目标元素列表。我想在嵌套它们时通过添加更多父元素以分别包装 randomElement 和节点来将它们展平,同时使目标子元素成为目标兄弟姐妹。我的意思是输出应该是这样的:
<document>
<div class='target-one'>
maybe some text node, maybe not...1
<randomElement>
maybe some text node, maybe not...2
</randomElement>
</div>
<div class='target-one'>
<randomElement>
maybe some text node, maybe not...3
</randomElement>
</div>
<div class='target-one'>
maybe some text node, maybe not...4
<randomElement>
maybe some text node, maybe not...5
</randomElement>
</div>
<div class='target-two'>
maybe some text node, maybe not...6
<randomElement>
maybe some text node, maybe not...7
</randomElement>
</div>
<div class='target-one'>
maybe some text node, maybe not...8
<randomElement>
maybe some text node, maybe not...9
</randomElement>
</div>
<div class='target-two'>
maybe some text node, maybe not...10
<randomElement>
maybe some text node, maybe not...11
</randomElement>
</div>
<div class='target-one'>
<randomElement>
maybe some text node, maybe not...12
</randomElement>
</div>
<div class='target-two'>
maybe some text node, maybe not...13
<randomElement>
maybe some text node, maybe not...14
</randomElement>
</div>
<div class='target-two'>
maybe some text node, maybe not...15
<randomElement>
maybe some text node, maybe not...16
</randomElement>
</div>
<div class='target-two'>
maybe some text node, maybe not...17
<randomElement>
maybe some text node, maybe not...18
</randomElement>
</div>
</document>
所以我最终得到了更多的父 div,但所有文本和其他节点都在正确的位置。请注意,randomElement 可能是一个不是目标类的 div...
这是为了重新格式化电子书以在在线图书馆中分页,因此在我们真正遇到问题 div 之前可能存在大量元素。因此,我们需要一些方法来选择问题子 div 之间的所有元素和文本节点作为一个组,因为如果它们都被包裹在自己的 div 中,那就没有用了——我们最终会得到每个 p、em 或 span 为自己的页面。
同时,大多数父 div 没有问题子级。只要解决方案通过它们,我就可以通过另一次运行清理任何空 div,但我确实需要它至少在基本级别上处理没有子元素的文本。
这是我在 StackOverflow 上的第一个问题,因为我没有得到必要的递归。
谢谢!
根据用户 52889 的回答进行编辑。这从来没有成功,但我把它留在这里是为了便于阅读:
我可以在撒克逊语中触发的 XSL:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"version="2.0">
<xsl:output method="html"
indent="yes"
encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="div[matches(@class,'target-one|target-two','i')]">
<xsl:for-each select="node()">
<xsl:choose>
<xsl:when test="self::*[matches(@class,'target-one|target-two','i')]">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:when test="preceding-sibling::node()[0][not(self::*[matches(@class,'target-one|target-two','i')])]">
<!-- do nothing, it will be handled by the next case -->
</xsl:when>
<xsl:otherwise>
<!--
create a copy of the element matched by the template, with its attrs
add to it the current node and all nodes which follow it, up to the next SIGNIFICANT node
or, put another way, all following siblings which either
a) do not have a preceding signficant node, or
b) whose nearest preceding singificant node is the same as the nearest preceding significant node of the current node, i.e. its following sibling node is the current node.
-->
<xsl:element name="{../name()}">
<xsl:apply-templates select="../@*"/>
<xsl:apply-templates select="following-sibling::node()[
not(preceding-sibling::*[matches(@class,'target-one|target-two','i')])
or
count(preceding-sibling::*[matches(@class,'target-one|target-two','i')][0]/following-sibling::node()[0] | current()) = 1
]" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
此文件的当前输出(包含子项和重复项):
<document>
<div class="target-one">
<randomElement>
maybe some text node, maybe not...2
</randomElement>
<div class="target-one"></div>
maybe some text node, maybe not...4
<randomElement>
maybe some text node, maybe not...5
</randomElement>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...7
</randomElement>
</div>
<div class="target-two"></div>
maybe some text node, maybe not...8
<randomElement>
maybe some text node, maybe not...9
</randomElement>
</div>
<div class="target-one">
<div class="target-one"></div>
maybe some text node, maybe not...4
<randomElement>
maybe some text node, maybe not...5
</randomElement>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...7
</randomElement>
</div>
<div class="target-two"></div>
maybe some text node, maybe not...8
<randomElement>
maybe some text node, maybe not...9
</randomElement>
</div>
<div class="target-one"></div>
<div class="target-one">
<randomElement>
maybe some text node, maybe not...5
</randomElement>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...7
</randomElement>
</div>
<div class="target-two"></div>
maybe some text node, maybe not...8
<randomElement>
maybe some text node, maybe not...9
</randomElement>
</div>
<div class="target-one">
<div class="target-two">
<randomElement>
maybe some text node, maybe not...7
</randomElement>
</div>
<div class="target-two"></div>
maybe some text node, maybe not...8
<randomElement>
maybe some text node, maybe not...9
</randomElement>
</div>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...7
</randomElement>
</div>
<div class="target-two"></div>
<div class="target-one">
<randomElement>
maybe some text node, maybe not...9
</randomElement>
</div>
<div class="target-one"></div>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...11
</randomElement>
<div class="target-one"></div>
maybe some text node, maybe not...13
<randomElement>
maybe some text node, maybe not...14
</randomElement>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...16
</randomElement>
</div>
<div class="target-two"></div>
maybe some text node, maybe not...17
<randomElement>
maybe some text node, maybe not...18
</randomElement>
</div>
<div class="target-two">
<div class="target-one"></div>
maybe some text node, maybe not...13
<randomElement>
maybe some text node, maybe not...14
</randomElement>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...16
</randomElement>
</div>
<div class="target-two"></div>
maybe some text node, maybe not...17
<randomElement>
maybe some text node, maybe not...18
</randomElement>
</div>
<div class="target-one"></div>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...14
</randomElement>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...16
</randomElement>
</div>
<div class="target-two"></div>
maybe some text node, maybe not...17
<randomElement>
maybe some text node, maybe not...18
</randomElement>
</div>
<div class="target-two">
<div class="target-two">
<randomElement>
maybe some text node, maybe not...16
</randomElement>
</div>
<div class="target-two"></div>
maybe some text node, maybe not...17
<randomElement>
maybe some text node, maybe not...18
</randomElement>
</div>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...16
</randomElement>
</div>
<div class="target-two"></div>
<div class="target-two">
<randomElement>
maybe some text node, maybe not...18
</randomElement>
</div>
<div class="target-two"></div>
</document>
【问题讨论】: