【发布时间】:2013-09-08 13:43:22
【问题描述】:
我需要将 XML 转换成类似于英文句子的东西。 例如以下 XML:
<event>
<criteria>
<and>A</and>
<and>B</and>
<and>
<or>
<and>C</and>
<and>D</and>
</or>
<or>E</or>
</and>
</criteria>
</event>
必须变成类似:
To meet the criteria event must have A and B and either C and D or E.
这是一个例子,但“and”和“or”条件可以进一步嵌套。
规则似乎是:
- 如果一个元素没有后续兄弟姐妹或子元素,则不会输出任何内容,您就完成了。
- 如果“and”或“or”有一个没有子代的后续兄弟,则输出后续兄弟的类型(“and”或“or”)。(例如,A 和 B;C 和 D;D或 E)
- 如果“and”后面有一个带有“or”子代的“and”兄弟,则输出“and either”(例如,and either C)。
- 不输出没有文本的元素。
我尝试了几种方法来生成此输出,但都没有成功。一个问题是没有得到正确的递归。我见过很多嵌套一个元素的 xslt 处理示例(例如,Item 可以由由其他 Item 组成的其他 Item 组成,等等),但是没有像“and”和“or”这样的两个元素的示例" 可以是兄弟姐妹和/或相互嵌套。 我尝试使用 xsl:template match= "and | or" 然后测试 "and" 或 "or",但我要么没有降到叶级别,要么以错误的顺序出现。
我想知道是否有人可以指出我处理此类结构的正确方向,和/或是否有人可以建议更好的结构来表示“布尔”句子。由于 XML 尚未最终确定,如果使处理更容易,可以对其进行修改。
注意:我使用的是 Saxon 9,可以使用 xslt 2.0 解决方案。
更多信息:
再次感谢@g-ken-holman。我喜欢建议的自上而下的方法,但我遇到了一些问题。我不确定为什么在肯的例子中和/或序列被更改为或/和。和/或顺序似乎是正确的。无论如何,我运行了这个例子并且它有效。但是,我总共收到了 5 个案例。它适用于前两个简单的情况,即所有的和或或,以及情况 5,即上面的情况。但是案例 3 和 4 没有用。这是 XML 和结果。
<event>
<example>3</example>
<criteria>
<or>
<op>A</op>
<op>B</op>
</or>
<and>
<op>C</op>
</and>
</criteria>
</event>
Result: To meet the criteria, event must have either A or B C
Expected: To meet the criteria, event must have either A or B and C
示例 4:
<event>
<example>4</example>
<criteria>
<and>
<op>A</op>
<op>B</op>
</and>
<and>
<or>
<op>C</op>
<op>D</op>
<op>E</op>
</or>
</and>
</criteria>
</event>
结果:要满足条件,事件必须有 A 和 B C 或 D 或 E 预期:要满足条件,事件必须具有 A 和 B 以及 C 或 D 或 E
我认为原因是 and/or or 仅在有多个 (position()>1) 测试时才输出。但这不会涵盖所有情况。也许如果节点数的 position()>1 = 1?
可以添加一个“either”元素,如果这样会更容易的话。
答案说明:
这对于 cmets 部分来说太长了,所以我在这里添加它。我相信@Ken 已经提供了答案,并且他建议的第二种方法是最好的。
如果我了解处理。我们正在匹配文档中的所有节点。我们匹配“事件”并首先执行,因为它嵌套在其他节点之外。然后,如果遇到“and”节点,我们会在“and”上得到一个匹配,然后我们迭代(for-each)该级别的所有“and”兄弟节点。我们不会为第一个节点输出单词“and”,因为测试“position() > 1”失败。我们总是使用 xls:text 输出一个空格。接下来我们从当前(上下文)节点()应用模板。这开始让我们沿着树向下走,因为我们现在只匹配“and”的子节点。如果我们接下来匹配一个“and”,我们将重复我们到目前为止所做的事情。如果我们接下来匹配一个“或”,我们会执行 match="or" 模板,它与“and”几乎相同,只是它输出单词“or”。但是,有两个可能的模板匹配“或”和 1]" priority="1">。priority="1" 将该匹配项的优先级设置为高于另一个“或”匹配项,因为除非指定了优先级, 匹配的默认优先级为 0.5. 因此如果当前 "or" 节点有 2 个子节点 (or[count(*) > 1]), 我们输出 "either" 然后调用这将允许较低优先级 "or"匹配运行。
我认为这是正确的,但我有一个问题。 操作数的文本如何输出?
【问题讨论】:
-
现在您将
and和or混合为兄弟姐妹,这正是我所避免的。 “任何一个”对你来说有多重要?我补充说,当or有两个操作数时......你其他时候想要吗? -
请参阅下面的我在示例 3 和 4 中的 cmets 的替代答案(只是为了我的样式表的期望而写的不正确。
-
谢谢@Ken。我认为“and either”对于可读性很重要。我认为在 or 有 2 个或更多操作数的情况下需要它。会在测试中更改为 or[count(*) > 1] 吗?我正在研究我对处理的理解,并将发布它的描述和一些问题。