【问题标题】:Newbie: XSLT Transformation to validate rules in XML document新手:XSLT 转换以验证 XML 文档中的规则
【发布时间】:2012-03-07 13:33:36
【问题描述】:

我是 XSLT 的新手。 我有一个 XML 文档,我需要使用 xslt 来验证 XML 文档中的某些规则。 XML 和 xsl 文件将在 xsltproc 工具中使用,输出将是简单的通过或失败。

示例 XML:

...

<Manager mincount="4" grade="10"...>
  <Employee id="1" grade="9" .... />
  <Employee id="2" grade="8" .... />
.....
</Manager>
  1. Manager(本例中为Employee)下的子节点数必须等于或大于mincount属性的值。
  2. 所有员工的等级必须低于经理等级。

感谢您的帮助! 蒂亚!

【问题讨论】:

    标签: xml xslt transformation xml-validation


    【解决方案1】:

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

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

    请参阅 http://www.w3schools.com/schema/ 以获得良好的教程。

    【讨论】:

    • +1 XSLT 用于 XML 文档的转换。该教程应该很好地学习如何验证
    • 来吧伙计们,也提供符合Foo Bar要求的XSD sn-p。
    • 据我所知,在 XSD 规范中只能提供等于非负整数的 minOccurs 属性值。但是这里需要引用父元素中的属性。是否有我不知道的更新版本的 XSD 可以做到这一点?如果不是,那么这个问题是有效的并且适合 XSLT。
    • XSD 1.1 的断言允许您使用有效的 XPath 2.0 表达式验证复杂类型。
    【解决方案2】:

    这是一个 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>
    

    【讨论】:

    • 在您的第一个示例中,您可以将函数更改为命名模板,然后它将是 XSL 1.0。不过,您还必须从 xsl:attribute 元素中取出“选择”属性。这将通过使用 AVT (w3.org/TR/xslt#attribute-value-templates) 来解决。
    • 非常感谢大家。非常感激!我发布了另一个类似的问题,其中包含输入 xml 文档的一些变体,stackoverflow.com/questions/9505086/…
    【解决方案3】:

    这是一个 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).
    

    【讨论】:

      猜你喜欢
      • 2012-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-11
      • 1970-01-01
      • 2017-05-31
      相关资源
      最近更新 更多