新手:XSLT转换以验证XML文档中的规则

时间:2012-02-16 06:13:49

标签: xml xslt transformation xml-validation

我是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. Manager下的子项数(本例中为Employee)必须等于或大于mincount属性的值。
  2. 所有员工的成绩必须低于经理级别。
  3. 感谢您的帮助! TIA!

3 个答案:

答案 0 :(得分:4)

请改用XSD架构。它旨在验证XML。

特别是您可能对XSD 1.1 assertions感兴趣。

有关优秀教程,请参阅http://www.w3schools.com/schema/

答案 1 :(得分:4)

这是一个提供通过/失败的XSLT 1.0选项。 “失败”中还有其他详细信息,但可以删除。它还将消息输出到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 /输出示例:

<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).

答案 2 :(得分:1)

这是一个XSLT,它检查mincount值与Employee的实际出现次数。请注意,使用了xsl:function,因此这需要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>