当前位置: 首页 > 知识库问答 >
问题:

使用XSLT将XML转换为嵌套AND/OR的“布尔”英语句子

何博涛
2023-03-14

我需要将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”条件可以嵌套得更远。

规则似乎是:

  • 如果一个元素没有以下兄弟姐妹或子元素,则没有任何输出,您就完成了。
  • 如果“和”或“或”有一个没有孩子的后续兄弟姐妹,则输出以下兄弟姐妹(“和”或“或”)的类型。(例如,A和B;C和D;D或E)
  • 如果"and"有一个跟随"和"有一个"或"子"的兄弟姐妹,则输出"和任一"(例如,和任一C)。
  • 没有文本的元素不会输出。

我尝试了几种生成此输出的方法,但都没有成功。一个问题是递归不正确。我见过很多xslt处理的示例,其中一个元素是嵌套的(例如,Item可以由其他Items组成,而其他Items则由其他Items组成,等等),但没有像“and”和“or”这样的两个元素可以是兄弟姐妹和/或相互嵌套的示例。我尝试过使用xsl:模板匹配="and|or"然后测试“and”或“or”,但我要么没有深入到叶子级别,要么事情以错误的顺序出现。

我想知道是否有人可以为我指出正确的方向来处理这样的结构,和/或是否有人可以建议更好的结构来表示“布尔”句子。因为XML尚未最终确定,如果可以使处理更容易,则可以对其进行修改。

注意:我使用的是Saxon 9,可以使用xslt 2.0解决方案

更多信息:

再次感谢@g-ken-holman。我喜欢建议的自上而下的方法,但我有一些问题。在Ken的例子中,我不确定为什么and/or序列更改为or/and。和/或顺序似乎正确。无论如何,我运行了这个示例,它成功了。然而,我总共收到了5个案例。它适用于前两个具有all和或or的简单情况,以及上述情况下的情况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

我认为原因是和/或只有在有多个(位置()时才会输出

如果这样会更容易,可以添加一个“任一”元素。

回答说明:

评论部分太长了,所以我在这里添加它。我相信@Ken已经提供了答案,他建议的第二种方法是最好的。

如果我了解处理过程。我们正在匹配文档中的所有节点。我们匹配“事件”,它首先执行,因为它嵌套在其他节点之外。然后,如果遇到一个“and”节点,我们会在“and”上找到一个匹配项,然后(为每个节点)迭代该级别的所有“and”同级。我们不会为第一个节点输出单词“and”,因为测试“position()

我认为这是正确的,但我有一个问题。操作数的文本如何被放入输出?

共有2个答案

狄峻熙
2023-03-14

这个替代答案具有相同的样式表逻辑(唯一的变化是示例编号的说明),但发布是为了解决示例3和4的编辑问题。

您有:

<event>
<example>3</example>
<criteria>
    <or>
        <op>A</op>
        <op>B</op>
    </or>
    <and>
        <op>C</op>
    </and>
</criteria>
</event>

我会写下与以下内容相同的内容,使用我的原始逻辑得出您想要的结果:

t:\ftemp>type boolean3.xml
<event>
<example>3</example>
<criteria>
  <and>
    <or>
        <op>A</op>
        <op>B</op>
    </or>
    <op>C</op>
  </and>
</criteria>
</event>
t:\ftemp>xslt2 boolean3.xml boolean2.xsl
3 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>

我会这样写:

t:\ftemp>type boolean4.xml
<event>
  <example>4</example>
  <criteria>
<and>
    <op>A</op>
    <op>B</op>
    <or>
        <op>C</op>
        <op>D</op>
        <op>E</op>
    </or>
</and>
  </criteria>
</event>
t:\ftemp>xslt2 boolean4.xml boolean2.xsl
4 To meet the criteria, event must have A and B and  C or D or E

在我的代码中,只有当有两个操作数时,我才使用单词“非此即彼”。。。我想当有两个以上的操作数时,它也可以工作,所以您可以将其添加到处理逻辑中。

以下是为适应示例编号而修改的样式表:

t:\ftemp>type boolean2.xsl
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.0">

<xsl:output method="text"/>

<!--eat white-space-->
<xsl:template match="text()[not(normalize-space())]"/>

<!--start result-->
<xsl:template match="event">
  <xsl:value-of select="example"/>
  <xsl:text> To meet the criteria, event must have</xsl:text>
  <xsl:apply-templates select="criteria"/>
</xsl:template>

<!--handle conjunction-->
<xsl:template match="and">
  <xsl:for-each select="*">
    <xsl:if test="position()>1"> and</xsl:if>
    <xsl:text> </xsl:text>
    <xsl:apply-templates select="."/>
  </xsl:for-each>
</xsl:template>

<!--handle alternation-->
<xsl:template match="or">
  <xsl:for-each select="*">
    <xsl:if test="position()>1"> or</xsl:if>
    <xsl:text> </xsl:text>
    <xsl:apply-templates select="."/>
  </xsl:for-each>
</xsl:template>

<!--special grammar case for alternation between 2 operands-->
<xsl:template match="or[count(*) = 2]" priority="1">
  <xsl:text> either</xsl:text>
  <xsl:next-match/>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>

所以,这完全取决于您如何编写XML。检查我如何将您所做的重新编写为操作数的工作方式,并询问您是否需要更多说明。

金承嗣
2023-03-14

我建议你总是“自上而下”处理数据,而不是试图与兄弟姐妹打交道。

以下是解决方案:

t:\ftemp>type boolean1.xml 
<event>
<criteria>
    <and>A</and>
    <and>B</and>
    <and>
        <or>
            <and>C</and>
            <and>D</and>
        </or>
        <or>E</or>
    </and>
</criteria>
</event>
t:\ftemp>call xslt2 boolean1.xml boolean1.xsl 

To meet the criteria, event must have A and B and  either  C and D or E
t:\ftemp>type boolean1.xsl 
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.0">

<xsl:output method="text"/>

<!--eat white-space-->
<xsl:template match="text()[not(normalize-space())]"/>

<!--start result-->
<xsl:template match="event">
To meet the criteria, event must have<xsl:apply-templates/>
</xsl:template>

<!--handle conjunction-->
<xsl:template match="*[child::and]">
  <xsl:for-each select="child::and">
    <xsl:if test="position()>1"> and</xsl:if>
    <xsl:text> </xsl:text>
    <xsl:apply-templates select="."/>
  </xsl:for-each>
</xsl:template>

<!--handle alternation-->
<xsl:template match="*[child::or]">
  <xsl:for-each select="child::or">
    <xsl:if test="position()>1"> or</xsl:if>
    <xsl:text> </xsl:text>
    <xsl:apply-templates select="."/>
  </xsl:for-each>
</xsl:template>

<!--special grammar case for alternation between 2 operands-->
<xsl:template match="*[count(child::or) = 2]" priority="1">
  <xsl:text> either</xsl:text>
  <xsl:next-match/>
</xsl:template>

<!--don't allow a mixture-->
<xsl:template match="*[child::and and child::or]" priority="2">
  <xsl:message terminate="yes">
    <xsl:text>A mixture of ands and ors is not allowed.</xsl:text>
  </xsl:message>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>rem Done! 

至于更改XML的建议,我建议使用一种不允许意外组合的结构,例如“当and和OR都是兄弟时该怎么办”。考虑以下因素:

t:\ftemp>type boolean2.xml 
<event>
<criteria>
  <and>
    <op>A</op>
    <op>B</op>
    <or>
      <and>
        <op>C</op>
        <op>D</op>
      </and>
      <op>E</op>
    </or>
  </and>
</criteria>
</event>
t:\ftemp>call xslt2 boolean2.xml boolean2.xsl 

To meet the criteria, event must have A and B and  either  C and D or E
t:\ftemp>type boolean2.xsl 
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.0">

<xsl:output method="text"/>

<!--eat white-space-->
<xsl:template match="text()[not(normalize-space())]"/>

<!--start result-->
<xsl:template match="event">
To meet the criteria, event must have<xsl:apply-templates/>
</xsl:template>

<!--handle conjunction-->
<xsl:template match="and">
  <xsl:for-each select="*">
    <xsl:if test="position()>1"> and</xsl:if>
    <xsl:text> </xsl:text>
    <xsl:apply-templates select="."/>
  </xsl:for-each>
</xsl:template>

<!--handle alternation-->
<xsl:template match="or">
  <xsl:for-each select="*">
    <xsl:if test="position()>1"> or</xsl:if>
    <xsl:text> </xsl:text>
    <xsl:apply-templates select="."/>
  </xsl:for-each>
</xsl:template>

<!--special grammar case for alternation between 2 operands-->
<xsl:template match="or[count(*) = 2]" priority="1">
  <xsl:text> either</xsl:text>
  <xsl:next-match/>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>rem Done! 

在第二种方法中,“动作”由元素触发,而不是由子操作数元素触发。我认为这会更直接。

注意,对于英语读者来说,在没有标点符号的情况下深度嵌套and和OR时,可能会遇到一些语法挑战。

 类似资料:
  • XML输入文件: XML输入文件转换为XML输出文件。将XML输入文件的firstName、middleName和lastName标签合并为XML Ouput文件的name标签,将XML输入文件的address1、address2、city、state和pincode标签合并为XML Ouput文件的address标签。 我几乎转换了代码,但我在这里与empId作斗争。我已经在XSLT文件中手动输

  • 我有以下问题。我不是XSLT方面最伟大的专家,我想成功的是将一个XML从赛贝斯转换为以下内容: Sybase的输出: 我希望它的输出标题保持原样,条目部分不同 这是到目前为止我的XSLT(对不起,不太可能) 也许,有人可以帮我实现我想要的。非常感谢你。

  • 问题内容: 我有一个带有三个字段(userId,标题,描述)的索引对象。我想找到标题或说明包含给定关键字的特定用户的所有对象。 我有这样的事情(但这显然是错误的): 如何修改代码以获取具有正确ID和标题或描述中的搜索短语的所有对象? 问题答案: 我认为将是这样的:

  • 问题内容: 我想使用xsl文件转换一些xml并以某种方式输出结果(我使用的是Android Api Level 8)。 我当前的活动看起来像这样,但是转换器保持为空。LogCat引发一个with ,表示xml格式不正确,但是我确定它是正确的。 我在LogCat中发现了一条提示,提示在上述错误消息之前。 我究竟做错了什么? 这是要转换的xml文件(source.xml) 这是对应的xsl(produ

  • 我想使用XSLT将一些XML转换为JSON。XML如下所示: 我希望JSON如下所示: 推荐的方法是什么? 我已经有了一个方法,它看起来不太好,因为它只适用于xslt 1.0(我认为)和文本块。请参阅此处:https://xsltfiddle.liberty-development.net/naZYrpy/1 我更喜欢使用xslt 3.0和xml to json函数的更有效方法,但似乎不可能添加额

  • 本文向大家介绍ASP.NET使用xslt将xml转换成Excel,包括了ASP.NET使用xslt将xml转换成Excel的使用技巧和注意事项,需要的朋友参考一下 序:   最近在给客户做一个管理系统的时候,客户提出要将查询结果导出到Excel。对于还是实习生的我倍感压力,于是找了点资料。网上有个示例,其中方法十分简单。于是照猫画虎,把方法和心得与大家分享。OK,Let`s go 第一步:   创