0

我是 XSD 的新手,很难创建 XSD 来验证以下传入的 XML 消息。

我遇到的困难是:

  1. 数据元素“Field”,其属性“position”值等于“FirstName”或“LastName”必须存在,并且只出现一次。
  2. 数据元素“Field”,其属性“position”值等于“MiddleName”是可选的。而如果出现,也只能出现一次。
  3. 日期元素“字段”将只有这三个子元素,如果“中间名”不存在,则只有两个。

有什么想法吗?


传入的原始 XML,需要 XSD 进行验证。

<Message>  
  <MessageTypeIndicator version="1" class="8" function="2" origin="3"/>
  <Fields>
     <Field position="FirstName">Jason</Field>
     <Field position="LastName">Smith</Field>
     <Field position="MiddleName">dk</Field>
  </Fields>
</Message>

稍后,我还将创建一个 XSLT 来将原始 XML 转换为以下内容:

<Person>
    <MessageTypeIndicator>
        <version>1</version>
        <class>8</class>
        <function>2</function>
        <origin>3</origin>
    </MessageTypeIndicator>
    <FirstName>Jason</FirstName>
    <LastName>Smith</LastName>
    <MiddleName>dk</MiddleName>
</Person>

以下是我迄今为止创建的未经验证的 xslt

    <?xml version="1.0" encoding="UTF-8"?>

    <xsl:stylesheet>
      <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
      <xsl:template match="/">
        <Message>      
          <MessageTypeIndicator>        
              <version>
                <xsl:value-of select="Message/MessageTypeIndicator/@version"/>
              </version>      
              <class>
                <xsl:value-of select="Message/MessageTypeIndicator/@class"/>            
              </class>      
              <function>
                <xsl:value-of select="Message/MessageTypeIndicator/@function"/>            
              </function>       
              <origin>
                <xsl:value-of select="Message/MessageTypeIndicator/@origin"/>            
              </origin>    
          </MessageTypeIndicator>
          <xsl:for-each select="Message/Fields/Field">
            <xsl:if test="@position='FirstName'">
              <FirstName>
              <xsl:value-of select="string(.)"/>
            </FirstName>
            </xsl:if>      
            <xsl:if test="@position='LastName'">
            <LastName>
              <xsl:value-of select="string(.)"/>
            </LastName>
            </xsl:if>      
            <xsl:if test="@position='MiddleName'">
            <MiddleName>
              <xsl:value-of select="string(.)"/>
            </MiddleName>
            </xsl:if>
          </xsl:for-each>
        </Message>
      </xsl:template>
    </xsl:stylesheet>
4

3 回答 3

2

您不能真正使用 XSD 1.0 进行这种检查 - 可以检查属性或元素是否存在,但不能检查元素是否存在其属性的特定值。

您可以很容易地做的是在 XSLT 中进行检查 - 如下所示:

<xsl:template match="Message">
  <xsl:if test="count(Fields/Field[@position='FirstName']) != 1">
    <xsl:message terminate="yes">The message must exactly one 'FirstName' field</xsl:message>
  </xsl:if>
  <xsl:if test="count(Fields/Field[@position='MiddleName']) > 1">
    <xsl:message terminate="yes">The message cannot contain multiple 'MiddleName' fields</xsl:message>
  </xsl:if>
  <xsl:if test="count(Fields/Field[@position!='MiddleName']) > 3">
    <xsl:message terminate="yes">Too many fields</xsl:message>
  </xsl:if>
  <Person>
    <MessageTypeIndicator>
      <version>1</version>
      <class>8</class>
      <function>2</function>
      <origin>3</origin>
    </MessageTypeIndicator>
    <FirstName>
      <xsl:value-of select="Fields/Field[@position='FirstName']"/>
    </FirstName>
    <LastName>
      <xsl:value-of select="Fields/Field[@position='LastName']"/>
    </LastName>
    <MiddleName>
      <xsl:value-of select="Fields/Field[@position='MiddleName']"/>
    </MiddleName>
  </Person>
</xsl:template>

将进行检查,然后进行转换。

于 2013-04-10T19:13:44.803 回答
1

此类验证无法在 XSD 1.0 中实现。您应该考虑使用XSD 1.1或使用Schematron

于 2013-04-10T19:08:52.863 回答
1

设计这个文档的人,通过使用非常抽象的元素名称(如 Message 和 Field),然后使用 MessageTypeIndicator 和 Position 等属性对它们进行专门化,可能认为他们通过设计灵活和可扩展的东西很聪明。他们不是;如果您使用具体元素,XML 已经足够灵活和可扩展了

<Person><First>Jason</First><Last>Smith</Last></Person>

除了使 XML 更难处理之外,额外的抽象级别没有任何作用,其中一个方面是您无法为其编写精确的模式。也许这正是设计师的想法:也许他们想保持它的灵活性和可扩展性,并且知道一旦人们开始编写模式,它就会失去他们如此努力(但徒劳无功)实现的灵活性和可扩展性。

于 2013-04-10T19:40:52.437 回答