Новичок: XSLT-преобразование для проверки правил в документе XML - PullRequest
4 голосов
/ 16 февраля 2012

Я новичок в XSLT.У меня есть документ XML, и мне нужно придумать xslt для проверки определенных правил в документе XML.Файлы XML и xsl будут использоваться в инструменте xsltproc, а на выходе будет простой Pass или Fail.

Пример XML:

...

<Manager mincount="4" grade="10"...>
  <Employee id="1" grade="9" .... />
  <Employee id="2" grade="8" .... />
.....
</Manager>
  1. Число детей в подчинении менеджера (в данном случае «Сотрудник») должно быть равно или большезначение атрибута mincount.
  2. Все оценки работника должны быть меньше, чем у менеджера.

Благодарим Вас за помощь!ТИА!

Ответы [ 3 ]

4 голосов
/ 16 февраля 2012

Вот опция XSLT 1.0, которая дает пропуск / сбой. В «Fail» есть дополнительная деталь, но ее можно удалить. Он также выводит сообщение как в stdout, так и в stderr и прекращает обработку.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>

  <xsl:template match="/Manager">
    <xsl:if test="not(count(Employee) >= @mincount)">
      <xsl:variable name="vMessage" select="concat('Fail - Number of Employees (',count(Employee),') is not >= to @mincount (',@mincount,').')"/>
      <!--stdout-->
      <xsl:value-of select="$vMessage" disable-output-escaping="yes"/> 
      <!--stderr-->
      <xsl:message terminate="yes"><xsl:value-of select="$vMessage"/></xsl:message>
    </xsl:if>
    <xsl:if test="Employee/@grade >= @grade">
      <xsl:variable name="vMessage" select="concat('Fail - Employee (id ',Employee[@grade >= ancestor::Manager/@grade][1]/@id,') has a grade (',Employee[@grade >= ancestor::Manager/@grade][1]/@grade,') that is higher than the Manager grade (',@grade,').')"/>
      <!--stdout-->
      <xsl:value-of select="$vMessage" disable-output-escaping="yes"/> 
      <!--stderr-->
      <xsl:message terminate="yes"><xsl:value-of select="$vMessage"/></xsl:message>
    </xsl:if>
    <xsl:text>Pass</xsl:text>
  </xsl:template>

</xsl:stylesheet>

Вот несколько примеров XML / output:

<Manager mincount="1" grade="7" id="28">
  <Employee id="6" grade="5"/>
  <Employee id="7" grade="1"/>
  <Employee id="8" grade="2"/>
  <Employee id="3" grade="7"/>
</Manager>

Fail - Employee (id 3) has a grade (7) that is higher than the Manager grade (7).

<Manager mincount="1" grade="7" id="28">
  <Employee id="6" grade="5"/>
  <Employee id="7" grade="1"/>
  <Employee id="8" grade="2"/>
  <Employee id="3" grade="6"/>
</Manager>

Pass

<Manager mincount="10" grade="7" id="28">
  <Employee id="6" grade="5"/>
  <Employee id="7" grade="1"/>
  <Employee id="8" grade="2"/>
  <Employee id="3" grade="6"/>
</Manager>

Fail - Number of Employees (4) is not >= to @mincount (10).
4 голосов
/ 16 февраля 2012

Вместо этого используйте схему XSD.Он предназначен для проверки XML.

В частности, вас могут заинтересовать утверждения XSD 1.1 .

. См. http://www.w3schools.com/schema/ для хорошего учебника.

1 голос
/ 16 февраля 2012

Вот XSLT, который проверяет значения mincount в сравнении с фактическим числом вхождений Employee.Обратите внимание, что функция xsl: используется, поэтому для этого требуется XSLT 2.0.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="http://localhost:8080/customFunctions" exclude-result-prefixes="custom">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:function name="custom:checkMgr">
        <xsl:param name="mgr"/>
        <xsl:choose>
            <xsl:when test="$mgr/@mincount &gt; count($mgr/Employee)">false</xsl:when>
            <xsl:when test="count($mgr/Employee[number(@grade) &gt;= number($mgr/@grade)]) &gt; 0">false</xsl:when>
           <xsl:otherwise>true</xsl:otherwise>
        </xsl:choose>
    </xsl:function>

    <xsl:template match="/">
        <root>
            <xsl:apply-templates select="root/Manager"/>
        </root>
    </xsl:template>

    <xsl:template match="Manager">
        <mgrCheck>
            <xsl:attribute name="id" select="@id"/>
            <xsl:attribute name="mincount" select="@mincount"/>
            <xsl:attribute name="actual" select="count(Employee)"/>
            <xsl:attribute name="grade" select="@grade"/>
            <xsl:attribute name="numEmpNoLessGrade" select="count(Employee[number(@grade) >= number(../@grade)])"/>
            <xsl:attribute name="OK" select="custom:checkMgr (.)"/>
        </mgrCheck>
    </xsl:template>
</xsl:stylesheet>

При применении к следующему входу:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <Manager mincount="4" grade="10" id="26">
        <Employee id="1" grade="9"/>
        <Employee id="2" grade="8"/>
    </Manager>
    <Manager mincount="1" grade="10" id="27">
        <Employee id="3" grade="9"/>
        <Employee id="4" grade="8"/>
        <Employee id="5" grade="4"/>
    </Manager>
    <Manager mincount="1" grade="7" id="28">
        <Employee id="6" grade="8"/>
        <Employee id="7" grade="7"/>
        <Employee id="8" grade="6"/>
        <Employee id="9" grade="9"/>
    </Manager>
    <Manager mincount="3" grade="9" id="29">
        <Employee id="10" grade="9"/>
        <Employee id="11" grade="8"/>
        <Employee id="12" grade="7"/>
    </Manager>
</root>

результат:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <mgrCheck id="26" mincount="4" actual="2" grade="10" numEmpNoLessGrade="0" OK="false"/>
    <mgrCheck id="27" mincount="1" actual="3" grade="10" numEmpNoLessGrade="0" OK="true"/>
    <mgrCheck id="28" mincount="1" actual="4" grade="7" numEmpNoLessGrade="3" OK="false"/>
    <mgrCheck id="29" mincount="3" actual="3" grade="9" numEmpNoLessGrade="1" OK="false"/>
</root>

Альтернативой в XSLT 1.0 может быть следующее:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/">
        <root>
            <xsl:apply-templates select="root/Manager"/>
        </root>
    </xsl:template>

    <xsl:template match="Manager">
        <mgrCheck>
            <id><xsl:value-of select="@id"/></id>
            <mincount><xsl:value-of select="@mincount"/></mincount>
            <actual><xsl:value-of select="count(Employee)"/></actual>
            <grade><xsl:value-of select="@grade"/></grade>
            <numEmpNoLessGrade><xsl:value-of select="count(Employee[@grade &gt;= ../@grade])"/></numEmpNoLessGrade>
            <OK>
                <xsl:choose>
                    <xsl:when test="@mincount &gt; count(Employee)">false</xsl:when>
                    <xsl:when test="count(Employee[@grade &gt;= ../@grade]) &gt; 0">false</xsl:when>
                    <xsl:otherwise>true</xsl:otherwise>
                </xsl:choose>
            </OK>
        </mgrCheck>
    </xsl:template>
</xsl:stylesheet>

с результатом

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <mgrCheck>
        <id>26</id>
        <mincount>4</mincount>
        <actual>2</actual>
        <grade>10</grade>
        <numEmpNoLessGrade>0</numEmpNoLessGrade>
        <OK>false</OK>
    </mgrCheck>
    <mgrCheck>
        <id>27</id>
        <mincount>1</mincount>
        <actual>3</actual>
        <grade>10</grade>
        <numEmpNoLessGrade>0</numEmpNoLessGrade>
        <OK>true</OK>
    </mgrCheck>
    <mgrCheck>
        <id>28</id>
        <mincount>1</mincount>
        <actual>4</actual>
        <grade>7</grade>
        <numEmpNoLessGrade>3</numEmpNoLessGrade>
        <OK>false</OK>
    </mgrCheck>
    <mgrCheck>
        <id>29</id>
        <mincount>3</mincount>
        <actual>3</actual>
        <grade>9</grade>
        <numEmpNoLessGrade>1</numEmpNoLessGrade>
        <OK>false</OK>
    </mgrCheck>
</root>
...