我需要将 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 和 BC 或 D 或 E 预期:要满足条件,事件必须具有 A 和 B 以及 C 或 D 或 E
我认为原因是 and/or or 仅在有多个 (position()>1) 测试时才输出。但这不会涵盖所有情况。也许如果节点数的位置()> 1 = 1?
如果这会使它更容易,可以添加“任何一个”元素。
回答注意事项:
这对于评论部分来说太长了,所以我在这里添加它。我相信@Ken 已经提供了答案,并且他建议的第二种方法是最好的。
如果我了解处理。我们正在匹配文档中的所有节点。我们匹配“事件”并首先执行,因为它嵌套在其他节点之外。然后,如果遇到“and”节点,我们会在“and”上得到一个匹配,然后我们迭代(for-each)该级别的所有“and”兄弟节点。我们不会为第一个节点输出单词“and”,因为测试“position() > 1”失败。我们总是使用 xls:text 输出一个空格。接下来我们从当前(上下文)节点()应用模板。这开始让我们沿着树向下走,因为我们现在只匹配“and”的子节点。如果我们接下来匹配一个“and”,我们将重复我们到目前为止所做的事情。如果我们接下来匹配一个“或”,我们会执行 match="or" 模板,这与“and”几乎相同 除了它输出单词“或”。但是,有两个可能的模板匹配“或”和 1]" priority="1">。priority="1" 将该匹配项的优先级设置为高于另一个“或”匹配项,因为除非指定了优先级, 匹配的默认优先级为 0.5. 因此如果当前 "or" 节点有 2 个子节点 (or[count(*) > 1]), 我们输出 "either" 然后调用这将允许较低优先级 "or"匹配运行。匹配的默认优先级为 0.5。因此,如果当前“or”节点有 2 个子节点(or[count(*) > 1]),我们输出“either”,然后调用将允许较低优先级的“or”匹配运行。匹配的默认优先级为 0.5。因此,如果当前“or”节点有 2 个子节点(or[count(*) > 1]),我们输出“either”,然后调用将允许较低优先级的“or”匹配运行。
我认为这是正确的,但我有一个问题。操作数的文本如何输出?