Логическое выражение в инструкции XML

#xml #xslt #xpath #xml-parsing

#xml #xslt #xpath #xml-синтаксический анализ

Вопрос:

добрый вечер.
У меня два вопроса:
1) Как я могу представить логические выражения в XML?
пример:

 <service> 
<rule> </rule> and <rule> </rule> 
<rule> </rule> or <rule> </rule> 
</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]
  

с наилучшими пожеланиями

Комментарии:

1. Пожалуйста, размещайте свои вопросы отдельно, поскольку они кажутся не связанными друг с другом. — Подсказка: потратьте немного больше времени и усилий на объяснение того, что вам нужно, особенно. зачем вам это нужно.

2. Чтобы добавить дополнительную информацию, мне изменить вопрос или добавить в качестве ответа?

3. Ответ на ваш вопрос «любым удобным для вас способом». Это действительно зависит от того, что (или кто) находится на принимающей стороне и что им нужно делать с этой информацией. Об этом вы нам практически ничего не сказали, но подойдет любой формат, который позволяет им выполнять свою работу. Это то, что обозначает X (расширяемый) в XML. — P.S. Смотрите также MathML как возможный стандарт.

Ответ №1:

Я считаю, что это выходит за рамки Stack Overflow, но, думаю, я бы сделал:

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

с match бытием all или any . Или вы могли бы использовать это как атрибут service .

Не уверен, что понял ваш второй вопрос, не хотите уточнить?

Комментарии:

1. Это неплохая идея, хотя концептуально all / any не является родственным элементом правил, а скорее атрибутом их родительского элемента — так почему бы не сделать это так же и в форме.

2. я изменил свой вопрос. с наилучшими пожеланиями

Ответ №2:

Ну, «лучшего» способа не существует, но одним из способов может быть наличие элемента operator для связи двух правил или, возможно, других операторов. Например, ваше первое правило rules=[role:admin or is_admin:1] может быть выражено следующим образом

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

Это также позволило бы использовать «вложенные» операторы. Например 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, поэтому вот некоторый XSLT, который можно использовать для «разбора» правил. Это делается для сопоставления элементов operator, а затем рекурсивно разбирает первый и второй операнды. Затем он выдает результат в зависимости от типа оператора. Элементы правила просто анализируются путем проверки, существует ли правило в параметре, содержащем все правила.

Попробуйте этот 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>
  

Если вам нужно «рекурсивное» решение, попробуйте этот 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>
  

Комментарии:

1. Как вы видите, роли рекурсивны. как я могу реализовать рекурсию в XSLT? например, если я введу в xsl: param «правила» значение «роль: администратор», xslt должен сказать, что с этим правилом связаны 2 действия: admin_required и list_service с наилучшими пожеланиями

2. На данный момент вам пришлось бы вызывать XSLT несколько раз, причем новые параметры являются результатом предыдущего вызова.

3. так что, нет способа получить все действия с помощью рекурсионного вызова? С наилучшими пожеланиями