XML语句中的布尔表达式

时间:2014-07-06 01:11:53

标签: xml xslt xpath xml-parsing

晚上好。
我有两个问题:
1)如何在XML中表示布尔表达式?
例如:

<service> 
<rule> </rule> and <rule> </rule> 
<rule> </rule> or <rule> </rule> 
</service> 

好的,我会解释我的问题。 我想实现一个推理引擎。 问题如下: service有一组操作,每个操作都有一组规则。 规则可以由逻辑运算符链接。 我想过使用XML来表示我的规则。了解规则X我想提取与此规则关联的所有操作。 例如

action=admin_required, service=identity, rules=[role:admin or is_admin:1]
action=service_role, service=, rules=[role:service]
action=get_service, service=identity, rules=[admin_required or service_role]
action=list_services, service=identity, rules=[admin_required and admin_service]
action=create_service, service=identity, rules=[admin_required]
action=update_service, service=identity, rules=[admin_required]

最好的问候

2 个答案:

答案 0 :(得分:1)

我认为这超出了Stack Overflow的范围,但我想我会这样做:

<service>
    <match>all</match>
    <rule>...</rule>
    <rule>...</rule>
</service>

matchallany。或者您可以将其作为service的属性。

不确定我理解你的第二个问题,需要详细说明吗?

答案 1 :(得分:1)

嗯,没有最好的&#34;但是,一种方法可能是使用运算符元素来链接两个规则,或者可能是其他运算符。例如,您的第一个规则rules=[role:admin or is_admin:1]可以表示为

  <rules>
     <operator type="or">
        <rule>role:admin</rule>
        <rule>is_admin:1</rule>
     </operator>
  </rules>

这将允许嵌套&#39;运营商也是。例如,rules=[role:admin or (is_admin:1 and role:tester)]可以表示为

  <rules>
     <operator type="or">
        <rule>role:admin</rule>
        <operator type="or">
           <rule>is_admin:1</rule>
           <rule>role:tester</rule>
       </operator>
     </operator>
  </rules>

您已对此XSLT进行了标记,因此这里有一些可用于解析&#39;的XSLT。规则。它通过匹配运算符元素,然后递归解析第一个和第二个操作数来实现。然后,它根据操作员类型给出结果。通过检查规则是否存在于包含所有规则的参数中,可以简单地解析规则元素。

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:param name="rules">role:admin</xsl:param>
   <xsl:variable name="checkrule" select="concat(',', $rules, ',')" />

   <xsl:template match="actions">
      <results>
         <xsl:apply-templates />
      </results>
   </xsl:template>

   <xsl:template match="action">
      <xsl:variable name="evaluate">
         <xsl:apply-templates select="rules/*" mode="rules" />
      </xsl:variable>
      <xsl:if test="$evaluate=1">
         <xsl:value-of select="@*"/>
         <xsl:text>;</xsl:text>
      </xsl:if>
   </xsl:template>

   <xsl:template match="operator" mode="rules">
      <xsl:variable name="left">
         <xsl:apply-templates select="*[1]" mode="rules" />
      </xsl:variable>
      <xsl:variable name="right">
         <xsl:apply-templates select="*[2]" mode="rules" />
      </xsl:variable>
      <xsl:choose>
         <xsl:when test="@type='or'">
            <xsl:choose>
               <xsl:when test="$left=1 or $right=1">1</xsl:when>
               <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
         </xsl:when>
         <xsl:when test="@type='and'">
            <xsl:choose>
               <xsl:when test="$left=1 and $right=1">1</xsl:when>
               <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
         </xsl:when>
      </xsl:choose>
   </xsl:template>

   <xsl:template match="rule" mode="rules">
      <xsl:choose>
         <xsl:when test="contains($rules, .)">1</xsl:when>
         <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

应用于此XML(代表您的所有操作)

<actions>
   <action name="admin_required">
      <rules>
         <operator type="or">
            <rule>role:admin</rule>
            <rule>is_admin:1</rule>
         </operator>
      </rules>
   </action>
   <action name="service_role">
      <rules>
            <rule>role:service</rule>
      </rules>
   </action>
   <action name="get_service">
      <rules>
         <operator type="or">
            <rule>admin_required</rule>
            <rule>admin_service</rule>
         </operator>
      </rules>
   </action>
   <action name="list_services">
      <rules>
         <operator type="and">
            <rule>admin_required</rule>
            <rule>admin_service</rule>
         </operator>
      </rules>
   </action>
   <action name="create_service">
      <rules>
            <rule>admin_required</rule>
      </rules>
   </action>
   <action name="update_service">
      <rules>
            <rule>admin_required</rule>
      </rules>
   </action>
</actions>

以下是输出

<results>admin_required;</results>

如果你想要一个递归的&#39;解决方案,尝试这个XSLT,它使用一个命名模板,该模板以前一次调用的结果递归调用。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:param name="rules">role:admin</xsl:param>
   <xsl:variable name="checkrule" select="concat(',', $rules, ',')"/>

   <xsl:template match="actions">
      <results>
         <xsl:call-template name="recursive"/>
      </results>
   </xsl:template>

   <xsl:template name="recursive">
      <xsl:param name="currentRules" select="$rules"/>
      <xsl:param name="currentResults"/>
      <xsl:variable name="newResults">
         <xsl:apply-templates select="action">
            <xsl:with-param name="currentRules" select="$currentRules"/>
         </xsl:apply-templates>
      </xsl:variable>
      <xsl:choose>
         <xsl:when test="$newResults != $currentResults">
            <xsl:call-template name="recursive">
               <xsl:with-param name="currentRules" select="concat($rules, ';', $newResults)"/>
               <xsl:with-param name="currentResults" select="$newResults"/>
            </xsl:call-template>
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="$currentResults"/>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

   <xsl:template match="action">
      <xsl:param name="currentRules"/>
      <xsl:variable name="evaluate">
         <xsl:apply-templates select="rules/*" mode="rules">
            <xsl:with-param name="currentRules" select="$currentRules"/>
         </xsl:apply-templates>
      </xsl:variable>
      <xsl:if test="$evaluate=1">
         <xsl:value-of select="@*"/>
         <xsl:text>;</xsl:text>
      </xsl:if>
   </xsl:template>

   <xsl:template match="operator" mode="rules">
      <xsl:param name="currentRules"/>
      <xsl:variable name="left">
         <xsl:apply-templates select="*[1]" mode="rules">
            <xsl:with-param name="currentRules" select="$currentRules"/>
         </xsl:apply-templates>
      </xsl:variable>
      <xsl:variable name="right">
         <xsl:apply-templates select="*[2]" mode="rules">
            <xsl:with-param name="currentRules" select="$currentRules"/>
         </xsl:apply-templates>
      </xsl:variable>
      <xsl:choose>
         <xsl:when test="@type='or'">
            <xsl:choose>
               <xsl:when test="$left=1 or $right=1">1</xsl:when>
               <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
         </xsl:when>
         <xsl:when test="@type='and'">
            <xsl:choose>
               <xsl:when test="$left=1 and $right=1">1</xsl:when>
               <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
         </xsl:when>
      </xsl:choose>
   </xsl:template>

   <xsl:template match="rule" mode="rules">
      <xsl:param name="currentRules"/>
      <xsl:choose>
         <xsl:when test="contains($currentRules, .)">1</xsl:when>
         <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

这会产生以下结果

<results>admin_required;get_service;create_service;update_service;</results>