Search code examples
xmlvalidationrelaxngrelaxng-compact

Validate mixed content containing exactly one text node with RNC


I'm trying to validate a mixed content element which should contain exactly one text node. Eg, this should validate:

<corner description="ff models, bc RC; high temperature,high vdd">
  <modelSection>fff_pre</modelSection>
  <var value="high">temperature</var>
  <var value="high">vdd</var>
  fff_pre_Thi_Vhi_Vhi
</corner>

but this should not:

<corner description="ff models, bc RC; high temperature,high vdd">
  <modelSection>fff_pre</modelSection>
  <var value="high">temperature</var>
  <var value="high">vdd</var>
  <!-- no text, invalid! -->
</corner>

I tried

corner = element corner {
  description,
  (
    modelSection
    & var+
    & xsd:string
  )
}

(where description, modelSection and var are previously defined) but while validating the first example above rnv reports a "text not allowed" error for fff_pre_Thi_Vhi_Vhi. Substituting & text for & xsd:string validates a textless <corner>, which I don't want. Feels like this must be simple and I'm overlooking something... Thanks for any advice.


Solution

  • When I try to run jing with your schema (after adding the missing bits and converting from rnc to rng), I get this error:

    /tmp/t2/test.rng:4:28: error: interleave of "string" or "data" element
    

    This error correspond to the part of the rng that defines the contents of the corner element.

    This suggest to me that you are running smack dab into the limitation specified in Section 7.2 of the Relax NG spec. In your case, you are trying to have an element which will accept as children other elements and a data pattern. The spec does not allow it.

    If you are generating the XML, you could solve the issue by generating a structure like this:

    <corner description="ff models, bc RC; high temperature,high vdd">
      <modelSection>fff_pre</modelSection>
      <var value="high">temperature</var>
      <var value="high">vdd</var>
      <data>fff_pre_Thi_Vhi_Vhi</data>
    </corner>
    

    With a rnc like this:

    corner = element corner {
      description,
      (
        modelSection
        & var+
        & data
      )
    }
    
    data = element data { xsd:string { minLength = "1" } }
    

    I used data as the name of the element but I would want something more specific than this in a final solution.