0

Is it possible to control the order of the attribute values in Relax NG? which can be achieved using xs:assert in schema?

XML:

<body>
 <h1 class="title">title</h1>
 <h2 class="subtitle">subtitle</h2>
 <p class="paragraph1">para text 1</p>
 <p class="paragraph2">Para text 2</p>
 <p class="paragraph3">Para text 2</p>
 </body>

The class value should be in order, paragraph1 should always come first and paragraph2 should come after paragraph1. The assert I tried in schema:

<xs:assert test="p[1]/@class = 'paragraph1'
and ((every $i in p[2] satisfies $i/@class = 'paragraph2')
and (every $i in p[3] satisfies $i/@class = 'paragraph3'))  "/>
VSe
  • 919
  • 2
  • 13
  • 29

1 Answers1

1

A (compact-syntax) RelaxNG grammar to express what the question describes could be written as:

start = element body { h1?, h2?, p.paragraph1?, p.paragraph2?, p.paragraph3? }
h1 = element h1 { text & attribute class { string } }
h2 = element h2 { text & attribute class { string } }
p.paragraph1 = element p { text & attribute class { string "paragraph1" } }
p.paragraph2 = element p { text & attribute class { string "paragraph2" } }
p.paragraph3 = element p { text & attribute class { string "paragraph3" } }

Expressed in the RelaxNG XML syntax:

<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="">
  <start>
    <element name="body">
      <optional>
        <ref name="h1"/>
      </optional>
      <optional>
        <ref name="h2"/>
      </optional>
      <optional>
        <ref name="p.paragraph1"/>
      </optional>
      <optional>
        <ref name="p.paragraph2"/>
      </optional>
      <optional>
        <ref name="p.paragraph3"/>
      </optional>
    </element>
  </start>
  <define name="h1">
    <element name="h1">
      <interleave>
        <text/>
        <attribute name="class">
          <data type="string"/>
        </attribute>
      </interleave>
    </element>
  </define>
  <define name="h2">
    <element name="h2">
      <interleave>
        <text/>
        <attribute name="class">
          <data type="string"/>
        </attribute>
      </interleave>
    </element>
  </define>
  <define name="p.paragraph1">
    <element name="p">
      <interleave>
        <text/>
        <attribute name="class">
          <value type="string">paragraph1</value>
        </attribute>
      </interleave>
    </element>
  </define>
  <define name="p.paragraph2">
    <element name="p">
      <interleave>
        <text/>
        <attribute name="class">
          <value type="string">paragraph2</value>
        </attribute>
      </interleave>
    </element>
  </define>
  <define name="p.paragraph3">
    <element name="p">
      <interleave>
        <text/>
        <attribute name="class">
          <value type="string">paragraph3</value>
        </attribute>
      </interleave>
    </element>
  </define>
</grammar>
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • Thank you. The element p should be declared each time? Then the relaxNG will be lengthy when we consider for the complex structure? Is there any other options? – VSe May 17 '17 at 06:06
  • 1
    For expressing the constraint you need in RelaxNG, I’m not aware of options other than declaring multiple p elements as the answer does. In the RelaxNG schema for HTML5 https://github.com/validator/validator/tree/master/schema/html5 where I’ve had need to express similar constraints, I’ve used the same pattern described in the answer—that is, declaring an element multiple times in the grammar, with each having a different required attribute value. Yeah I guess it is relatively verbose but at least it’s a lot less verbose in the compact syntax compared to expressing it in XML. – sideshowbarker May 17 '17 at 06:12
  • Hi sideshowbaker, I tried to use the same RNC of html5 form Nu, but I am getting dataLibrary error in jing. Is it possible to use this RNC and tweaking them on my requirement? – VSe May 17 '17 at 10:02
  • @Senthil I think you want to pose a separate new question with the RNC you’re trying, and the error message – sideshowbarker May 17 '17 at 10:42
  • The OP sated "paragraph2 should come after paragraph1". However, the schema suggested here allows ``

    `` to be the first ``p`` element in ``body`` and thus not be preceded by an element marked with the class ``paragraph1``. Take the OP's example XML and delete the first ``p`` element, and it will validate. Seems to me it is not just the order that the OP is trying to get right but also to have a consecutive sequence which starts from 1. @Senthil please chime in.

    – Louis May 17 '17 at 12:50
  • Hi Louis, the schema suggested allows

    even paragraph1 not present, this is because all the p are declared as optional. If we take the before each p, then it will ask for paragraph1 first.

    – VSe May 18 '17 at 03:37
  • @sideshowbarker, I tried to restrict the RNC using interleave option and tried something like start = element body { h1?, h2?, p.paragraph1+ & p.paragraph2? & p.paragraph3? } to make the paragraph1 as mandatory and to make 2 and 3 anywhere. But I ended up with an error "p can occure in more than one operand of interleaves." Is there any possible way to do this? – VSe May 22 '17 at 10:39
  • VSr did what you tried not work? Whatever you need to do, I’m pretty sure it can be expressed with RelaxNG—though as @Louis pointed out it may need to be more complex than what’s in this answer. And it may end up being relatively verbose – sideshowbarker May 22 '17 at 10:42
  • `

    title

    subtitle

    Para text 2

    para text 1

    Para text 2

    `
    – VSe May 22 '17 at 10:46
  • VSr OK I suggest posting it as a separate question. That’s the best way to get the attention of the most people and to get the best answer most quickly – sideshowbarker May 22 '17 at 10:48
  • @sideshowbarker, Yes I created one http://stackoverflow.com/questions/44111198/interleave-in-rnc – VSe May 22 '17 at 11:09