Question

Say I have the following XML document:

<root>
  <genres> 
    <genre name="comedy" />
    <genre name="academic" />
  </genres>
  <authors>
    <author name="Thomson">
      <writings>
        <writing genre="academic">The text book</writing>
        <writing genre="comedy">The worst comedy</writing>
      <writings>
    </author>
  </authors>
  <readers>
    <reader name="Phil">
      <read writenBy="Thomson">The text book</read>
    </reader>
    <reader name="John" />
  </readers>
</root>

As you can see, a 'reader' element may not have 'read' childs.
However, I want the validation process to make sure there aren't entries like:

<reader name="Paul">
  <read writtenBy="Thomson">A writing the author never wrote</read>
</reader>

What I can do is limit the values an attribute can take based on previously defined attributes by using keys and keyrefs (see accepted answer). Based on that I can make sure the 'writtenBy' attribute actually refers to an author's name, or a writing's genre attribute comes from a previously defined genre.

I know you can hard code enumerations on an XSD document (see accepted answer).
Also, you may use assertions (in XSD 1.1) to have more flexible enumerations based on information contained on the XML (see accepted answer).
But I can't use these apporaches because they are hard coded. Is there a way to do a similar check for element values like I'm currently doing it with attribute values?

Was it helpful?

Solution

There are a few possibilities. First, you might be able to do something clever with key and keyref that checks that the content of a read element is the content of a writing element by the appropriate author.

It would be simpler, though, to give each writing an ID, and just make the read element refer to that ID. If you eliminate the redundancy, you eliminate the need to check for consistency. For display purposes, of course, you can always use XSLT to fetch the names of the author and the writing.

If you cannot push key and keyref any further, and you don't want to eliminate the redundancy in your XML representation, then the easiest way to check the constraint you specify is with an assertion, either in XSD 1.1 or in Schematron.

Of these, I'd recommend the second (restructure the XML to make the validity constraints simpler and easier to check). Your preference, of course, may differ.

OTHER TIPS

If I understand you requirement correctly, key/keyref can ALMOST handle it. At the level of the common ancestor (root), you would want to define a key with

* selector = authors/author/writings/writing
* fields = 
  (a) ../../@name 
  (b) .

and define a keyref with

* selector = readers/reader/read
* fields =
  (a) @writtenBy
  (b) .

The only problem is that you can't use ../../@name - you can't refer to an attribute of an ancestor in the XPath subset allowed for keys and keyrefs. I can't see a solution to this other than either (a) changing the XML design to copy author name in the "writing" element, or (b) using XSD 1.1 assertions instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top