Index: tools/langtool =================================================================== --- tools/langtool (revision 0) +++ tools/langtool (revision 0) @@ -0,0 +1,377 @@ +#!/usr/bin/perl -s +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# +# Copyright (C) 2006 - 2007 by Daniel Stenberg +# Copyright (C) 2007 - 2008 by Jonas Häggqvist +# + +# TODO: +# - Use getopts +# - Add common language-manipulations (tries to work on all languages by default): +# langtool --action [options] [--ids IDS] lang1 [..lang2] +# * --deprecate --id LANG_YES,LANG_NO *.lang +# * --changesource "Slight modification to english.lang" --id LANG_YES *.lang +# * --changeid LANG_YEAH -id LANG_YES *.lang +# * --modifytarget masd masd,recording --id LANG_YES,LANG_NO dansk.lang english.lang +# * --changedesc "Yes means no" --id LANG_YES dansk.lang english.lang +# * --sort --base english.lang dansk.lang norsk.lang +# * --validate dansk.lang +# +# Some obvious things: Change an ID in all languages, deprecate a string in all languages, change an English string in english.lang and change accordingly in other languages (for minor changes that don't require changes in translations), change desc in all languages (for minor changes that don't require attention by translators) +# + +# binary version for the binary lang file +my $langversion = 4; # 3 was the latest one used in the v1 format + +# A note for future users and readers: The original v1 language system allowed +# the build to create and use a different language than english built-in. We +# removed that feature from our build-system, but the build scripts still had +# the ability. But, starting now, this ability is no longer provided since I +# figured it was boring and unnecessary to write support for now since we +# don't use it anymore. + +use strict; +use warnings; +use encoding 'utf8'; +use XML::LibXML; +use File::Basename; +# The vars we may receive on the commandline. Or strict mode will kill us dead +use vars qw($p $b $u $e $t $i $o $v); + +if(!$ARGV[0]) { + print < + + -p= + Make the tool create a [prefix].c and [prefix].h file. + + -b= + Make the tool create a binary language (.lng) file named [outfile]. + The use of this option requires that you also use -e, -t and -i. + + -u + Update language file. Given the translated file and the most recent english + file, you\'ll get an updated version sent to stdout. Suitable action to do + when you intend to update a translation. + + -e= + Point out the english (original source) file, to use that as master + language template. Used in combination with -b or -u. + + -t= + Specify which target you want the translations/phrases for. Required when + -b or -p is used. + + The target can in fact be specified as numerous different strings, + separated with colons. This will make langtool to use all the specified + strings when searching for a matching phrase. + + -i= + The target id number, needed for -b. + + -o + Voice mode output. Outputs all id: and voice: lines for the given target! + + -v + Enables verbose (debug) output. +MOO + ; + exit; +} + +# How update works: +# +# 1) scan the english file, keep the whole for each phrase. +# 2) read the translated file, for each end of phrase, compare: +# A) all source strings, if there's any change there should be a comment about +# it output +# B) the desc fields +# +# 3) output the phrase with the comments from above +# 4) check which phrases that the translated version didn't have, and spit out +# the english version of those +# + +my $prefix = $p; +my $binary = $b; +my $update = $u; + +my $english = $e; +my $voiceout = $o; + +my $check = ($binary?1:0) + ($prefix?1:0) + ($update?1:0) + ($voiceout?1:0); + +if($check > 1) { + print "Please use only one of -p, -u, -o and -b\n"; + exit; +} +if(!$check) { + print "Please use at least one of -p, -u, -o and -b\n"; + exit; +} + +if(($binary || $update || $voiceout) && !$english) { + print "Please use -e too when you use -b, -o or -u\n"; + exit; +} + +my $target_id = $i; +if($binary && !$target_id) { + print "Please specify a target id number (with -i)!\n"; + exit; +} + +my $target = $t; +if(!$target && !$update) { + print "Please specify a target (with -t)!\n"; + exit; +} +my $verbose=$v; + +my $input = $ARGV[0]; + +# Figure out what to do +if ($update) { + update($input, $english); +} +elsif ($binary) { + binary($input, $binary, $english, $target, $target_id, $langversion); +} +elsif ($voiceout) { + voiceout($input, $english, $target); +} +elsif ($prefix) { + prefix($input, $prefix, $target); +} + +# Function definitions start here + +sub validate { + my ($input, $inputfile) = @_; + my $xmlschema; + my $res; + + $xmlschema = XML::LibXML::Schema->new( location => dirname($0) . '/language.xsd' ); + $res = eval { $xmlschema->validate($input); }; + # Die and notify if errors occured (not too helpful error messages unfortunately): + die "Error: $inputfile is not a valid languagefile\n" . $@ if $@; +} + +# Read in a languagefile, validate it and return the language as well as +# an ID => node_id map +sub readlangfile { + my ($langfile, $target) = @_; + my $lang; + my %idpos; + + # Read in langfile and validate against our schema + $lang = XML::LibXML->new->parse_file($langfile); + validate($lang, $langfile); + + # Remove strings we don't want + if ($target ne "ALL") { + my $phrases = $lang->getElementsByTagName("phrase"); + # If the target match is none, remove this phrase from the tree + for (my $i = 1; $i <= $phrases->size(); $i++) { + my $phrase = $phrases->get_node($i); + if ($target ne "ALL" && gettarget($phrase, "source", $target) eq "none") { + $lang->documentElement()->removeChild($phrase); + } + } + } + + # Find out where phrases are located in the input tree + my $phrases = $lang->getElementsByTagName("phrase"); + for (my $i = 1; $i <= $phrases->size(); $i++) { + $idpos{$phrases->get_node($i)->getAttribute("id")} = $i; + } + return ($lang, \%idpos); +} + +sub readenglish { + my ($englishfile, $target) = @_; + my %idmap; + my $idcount=0; # counter for lang ID numbers + my $voiceid=0x8000; # counter for voice-only ID numbers + + my ($english, $idpos) = readlangfile($englishfile, $target); + + # Make a map of numeric IDs for the phrases - used for binary and .c/.h + # files + my $phrases = $english->getElementsByTagName("phrase"); + + for (my $i = 1; $i <= $phrases->size(); $i++) { + my $numid; + my $id = $phrases->get_node($i)->getAttribute("id"); + if ($id =~ /^VOICE/) { + $numid = $voiceid++; + } + else { + $numid = $idcount++; + } + $idmap{$numid} = $id; + } + return ($english, \%idmap, $idpos, $idcount, $voiceid); +} + +sub prefix { + my ($inputfile, $prefix, $target) = @_; + my ($english, $idmap, $idpos, $idcount, $voiceid) = readenglish($inputfile, $target); + my $phrases = $english->getElementsByTagName("phrase"); + + open(HFILE, ">$prefix.h") || + die("Error: couldn't create file $prefix.h\n"); + open(CFILE, ">$prefix.c") || + die("Error: couldn't create file $prefix.c\n"); + + print HFILE <{$_}, $_); + my $phrase = $phrases->get_node($idpos->{$idmap->{$_}}); + my $string = gettarget($phrase, "source", $target); + printf(CFILE " \"%s\\0\"\n", $string); + } + print(HFILE " LANG_LAST_INDEX_IN_ARRAY, /* this is not a string, this is a marker */\n"); + print(HFILE " /* --- below this follows voice-only strings --- */\n"); + print(HFILE " VOICEONLY_DELIMITER = 0x8000,\n"); + + for (0x8000 .. $voiceid-1) { + printf(HFILE " %s,\n", $idmap->{$_}); + } + # Wrap up the files. + print(HFILE "\n};\n/* end of generated enum list */\n"); + print(CFILE ";\n/* end of generated string list */\n"); + close(HFILE); + close(CFILE); +} + +# This helper function picks the correct out of a number or elements, +# by matching the element's name attribute with the given target-string +sub gettarget { + my ($phrase, $section, $targetstring) = @_; + my $targetElements = $phrase->getElementsByTagName($section)->get_node(0)->getElementsByTagName("target"); + # Attempt to match against * as a last resort + for my $target (split(":", $targetstring.":*")) { + for (my $i = 0; $i < $targetElements->size(); $i++) { + # With this level of nesting, let's be happy that we aren't + # working on much data + for my $test (split(",", $targetElements->get_node($i)->getAttribute("name"))) { + # TODO: accept ipod* as a match for ipodvideo + if ($target eq $test) { + return $targetElements->get_node($i)->textContent; + } + } + } + } +} + +# This function updates a given inputfile and writes out the new +# languagefile with notes about missing and/or changed strings +sub update { + my ($inputfile, $englishfile) = @_; + + # Initial tango + my ($input, $english, $inputidpos, $idmap) = readlanguages($inputfile, $englishfile); + + my $inputPhrases = $input->getElementsByTagName("phrase"); + # Loop through English phrases + my $englishPhrases = $english->getElementsByTagName("phrase"); + for (my $i = 0; $i < $englishPhrases->size(); $i++) { + # Extract the english phrase for good luck + my $englishPhrase = $englishPhrases->get_node($i); + my $id = $englishPhrase->getAttribute("id"); + # Extract the input phrase from the input tree at the location + # we found in the first loop + + # Check for the following cases: + # 1. Phrase is missing entirely + if (!defined($$inputidpos{$id})) { + $englishPhrase->setAttribute("note", "This string was not available in the translation"); + $input->documentElement()->appendChild($englishPhrase); + } + else { + my $inputPhrase = $inputPhrases->get_node($$inputidpos{$id}); + + # 2. Desc differs from the one used when translating + if ($inputPhrase->getAttribute("desc") + ne $englishPhrase->getAttribute("desc")) { + $inputPhrase->setAttribute("note", sprintf("Desc differs: %s -- %s", $inputPhrase->getAttribute("desc"), $englishPhrase->getAttribute("desc"))); + } + + # 3. A + my $englishSources = $englishPhrase->getElementsByTagName("source")->get_node(0)->getElementsByTagName("target"); + for (my $j = 0; $j < $englishSources->size(); $j++) { + } + } + } + print($input->toString(1)); +} + +# This function generates a new binary languagefile +sub binary { + my ($inputfile, $outputfile, $englishfile, $target, $target_id, $langversion) = @_; + + # Initial tango + my ($input, $idpos) = readlangfile($inputfile, $target); + my ($english, $idmap, undef, $idcount, undef) = readenglish($englishfile, $target); + my %idmap_r; + + while (my ($key, $value) = each %$idmap) { + $idmap_r{$value}=$key; + } + + open(OUTF, ">$outputfile") or die("Can't create $outputfile"); + binmode(OUTF, ":utf8"); + printf(OUTF "\x1a%c%c", $langversion, $target_id); # magic lang file header + + # Loop through input phrases and write out the language file with the + # numeric ids from our map + my $inputPhrases = $input->getElementsByTagName("phrase"); + for ($i = 1; $i <= $inputPhrases->size(); $i++) { + my $phrase = $inputPhrases->get_node($i); + my $id = $phrase->getAttribute("id"); + my $dest = gettarget($phrase, "dest", $target); + my $numid = $idmap_r{$id}; + if ($numid < 0x8000) { + printf(OUTF "%c%c%s\x00", ($numid>>8), ($numid&0xff), $dest); + } + } + close(OUTF); +} Property changes on: tools/langtool ___________________________________________________________________ Added: svn:executable + * Index: tools/voice.pl =================================================================== --- tools/voice.pl (revision 19440) +++ tools/voice.pl (working copy) @@ -320,7 +320,7 @@ } } -# Run genlang and create voice clips for each string +# Run langtool and create voice clips for each string sub generateclips { our $verbose; my ($language, $target, $encoder, $encoder_opts, $tts_engine, $tts_engine_opts) = @_; @@ -328,7 +328,7 @@ my $langfile = dirname($0) . '/../apps/lang/' . $language . '.lang'; my $id = ''; my $voice = ''; - my $cmd = "genlang -o -t=$target -e=$english $langfile 2>/dev/null"; + my $cmd = "langtool -o -t=$target -e=$english $langfile 2>/dev/null"; my $pool_file; open(VOICEFONTIDS, "> voicefontids"); my $i = 0; Index: tools/genlang =================================================================== --- tools/genlang (revision 19440) +++ tools/genlang (working copy) @@ -607,7 +607,7 @@ my $name=$idnum[$i - 1]; # get the ID my $dest = $dest{$name}; # get the destination phrase - $dest =~ s:\"$:\\0\":; # insert a \0 before the second quote +# $dest =~ s:\"$:\\0\":; # insert a \0 before the second quote if(!$dest) { # this is just to be on the safe side @@ -650,6 +650,7 @@ # Now, make sure we get the number from the english sort order: $idnum = $idmap{$name}; + printf("%03d %s\n", $numid, $dest); printf OUTF ("%c%c%s\x00", ($idnum>>8), ($idnum&0xff), $dest); } } Index: tools/langv2toxml =================================================================== --- tools/langv2toxml (revision 0) +++ tools/langv2toxml (revision 0) @@ -0,0 +1,131 @@ +#!/usr/bin/perl +# XML::LibXML documentation: http://cpan.uwinnipeg.ca/htdocs/XML-LibXML/ + +use XML::LibXML; +use File::Basename; +use Switch; +use strict; + +sub trim { + my ($string) = @_; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} + +if ($#ARGV < 0) { + print("Usage: langv2toxml languagename\n"); + exit 1; +} + +my $i = 0; +my $currentNode = "language"; +my $comment = ''; +my $ns = 'http://www.rockbox.org/language'; +my $xmlschema; +my $res; + +# Used to hold various nodes +my %nodes; + +# Initialize our document +my $doc = XML::LibXML::Document->new('1.0', 'UTF-8'); +$nodes{'language'} = $doc->createElement("language"); +$nodes{'language'}->setAttribute('name', $ARGV[0]); + +# Set our namespace +$nodes{'language'}->setNamespace($ns); + +# Add a non-active namespace for the schemaLocation +$nodes{'language'}->setNamespace('http://www.w3.org/2001/XMLSchema-instance', 'xsi', 0); +$nodes{'language'}->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation', 'http://www.rockbox.org/language language.xsd'); +$doc->setDocumentElement($nodes{'language'}); + +while () { + my $line = $_; + $i++; + + # Current line is a comment + if ($line =~ /^#/) { + # Attempt to allow multiline comments by remembering if we're in + # a stream of comments. Not strictly necessary, but there you go + if ($comment eq "") { + $comment = "\n"; + } + # Remove the comment sign + $line =~ s/^#+//; + #if (trim($line) ne "") { + $comment .= $line; + #} + } + # Current line is something that isn't a comment + else { + # End any unclosed comments + if ($comment ne "") { + $nodes{'comment'} = $doc->createComment($comment); + $comment = ''; + if ($currentNode eq "source" + || $currentNode eq "dest" + || $currentNode eq "language") { + $nodes{$currentNode}->appendChild($nodes{'comment'}); + $nodes{'comment'} = undef; + } + } + + # If it's not a comment, we don't care about whitespace, so trim it + $line = trim($line); + + # A start-"tag" is encountered + if ($line =~ /^<([a-z]*)>$/) { + $currentNode = $1; + # Yeah, this could be easier done with a hash.. + $nodes{$1} = $doc->createElementNS($ns, $1); + if (defined($nodes{'comment'})) { + $nodes{$1}->appendChild($nodes{'comment'}); + $nodes{'comment'} = undef; + } + } + # An end-"tag" is encountered + elsif ($line =~ /^<\/([a-z]*)>$/) { + my $parent; + switch($1) { + case 'phrase' { $parent = 'language'; } + case (['dest', 'source', 'voice']) { $parent = 'phrase'; } + else { die sprintf("Unknown tag %s on line %d\n", $1, $i); } + } + $nodes{$parent}->appendChild($nodes{$1}); + } + # An id: value pair is encountered + elsif ($line =~ /^([a-z0-9*,_-]+)\s*:\s*"?(.*?)"?$/) { + switch($currentNode) { + case 'phrase' { + $nodes{$currentNode}->setAttribute($1, $2); + } + case (['dest', 'source', 'voice']) { + my $temp = $doc->createElementNS($ns, 'target'); + $temp->setAttribute('name', $1); + $temp->appendTextNode($2); + $nodes{$currentNode}->appendChild($temp); + } + } + } + elsif ($line ne "") { + printf(STDERR "Line %d confused me: %s\n", $i, $line); + } + } +} + +# Validate the schema (probably not strictly necessary) +$xmlschema = XML::LibXML::Schema->new( location => dirname($0) . '/XMLSchema.xsd' ); +$res = eval { $xmlschema->validate(XML::LibXML->new->parse_file(dirname($0) . '/language.xsd')); }; +# Notify if errors occured (not too helpful error messages unfortunately): +die $@ if $@; + +# Validate the document against our schema +$xmlschema = XML::LibXML::Schema->new( location => dirname($0) . '/language.xsd' ); +$res = eval { $xmlschema->validate($doc); }; +# Notify if errors occured (not too helpful error messages unfortunately): +die $@ if $@; + +# Else print our document to stdout +print($doc->toString(1)); Property changes on: tools/langv2toxml ___________________________________________________________________ Added: svn:executable + * Index: tools/language.xsd =================================================================== --- tools/language.xsd (revision 0) +++ tools/language.xsd (revision 0) @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: tools/XMLSchema.xsd =================================================================== --- tools/XMLSchema.xsd (revision 0) +++ tools/XMLSchema.xsd (revision 0) @@ -0,0 +1,2534 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]> + + + + Part 1 version: Id: structures.xsd,v 1.2 2004/01/15 11:34:25 ht Exp + Part 2 version: Id: datatypes.xsd,v 1.3 2004/01/23 18:11:13 ht Exp + + + + + + The schema corresponding to this document is normative, + with respect to the syntactic constraints it expresses in the + XML Schema language. The documentation (within <documentation> elements) + below, is not normative, but rather highlights important aspects of + the W3C Recommendation of which this is a part + + + + + The simpleType element and all of its members are defined + towards the end of this schema document + + + + + + Get access to the xml: attribute groups for xml:lang + as declared on 'schema' and 'documentation' below + + + + + + + + This type is extended by almost all schema types + to allow attributes from other namespaces to be + added to user schemas. + + + + + + + + + + + + + This type is extended by all types which allow annotation + other than <schema> itself + + + + + + + + + + + + + + + + This group is for the + elements which occur freely at the top level of schemas. + All of their types are based on the "annotated" type by extension. + + + + + + + + + + + + + This group is for the + elements which can self-redefine (see <redefine> below). + + + + + + + + + + + + + A utility type, not for public use + + + + + + + + + + + A utility type, not for public use + + + + + + + + + + + A utility type, not for public use + + #all or (possibly empty) subset of {extension, restriction} + + + + + + + + + + + + + + + + + A utility type, not for public use + + + + + + + + + + + + + A utility type, not for public use + + #all or (possibly empty) subset of {extension, restriction, list, union} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for maxOccurs + + + + + + + + + + + + for all particles + + + + + + + for element, group and attributeGroup, + which both define and reference + + + + + + + + 'complexType' uses this + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This branch is short for + <complexContent> + <restriction base="xs:anyType"> + ... + </restriction> + </complexContent> + + + + + + + + + + + + + + + Will be restricted to required or forbidden + + + + + + Not allowed if simpleContent child is chosen. + May be overriden by setting on complexContent child. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This choice is added simply to + make this a valid restriction per the REC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Overrides any setting on complexType parent. + + + + + + + + + + + + + + + This choice is added simply to + make this a valid restriction per the REC + + + + + + + + + + + + + + + + + No typeDefParticle group reference + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A utility type, not for public use + + #all or (possibly empty) subset of {substitution, extension, + restriction} + + + + + + + + + + + + + + + + + + + + + + + + + The element element can be used either + at the top level to define an element-type binding globally, + or within a content model to either reference a globally-defined + element or type or declare an element-type binding locally. + The ref form is not allowed at the top level. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + group type for explicit groups, named top-level groups and + group references + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + group type for the three kinds of group + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This choice with min/max is here to + avoid a pblm with the Elt:All/Choice/Seq + Particle derivation constraint + + + + + + + + + + restricted max/min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Only elements allowed inside + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple type for the value of the 'namespace' attr of + 'any' and 'anyAttribute' + + + + Value is + ##any - - any non-conflicting WFXML/attribute at all + + ##other - - any non-conflicting WFXML/attribute from + namespace other than targetNS + + ##local - - any unqualified non-conflicting WFXML/attribute + + one or - - any non-conflicting WFXML/attribute from + more URI the listed namespaces + references + (space separated) + + ##targetNamespace or ##local may appear in the above list, to + refer to the targetNamespace of the enclosing + schema or an absent targetNamespace respectively + + + + + + A utility type, not for public use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A subset of XPath expressions for use +in selectors + A utility type, not for public +use + + + + The following pattern is intended to allow XPath + expressions per the following EBNF: + Selector ::= Path ( '|' Path )* + Path ::= ('.//')? Step ( '/' Step )* + Step ::= '.' | NameTest + NameTest ::= QName | '*' | NCName ':' '*' + child:: is also allowed + + + + + + + + + + + + + + + + + + + + + + + A subset of XPath expressions for use +in fields + A utility type, not for public +use + + + + The following pattern is intended to allow XPath + expressions per the same EBNF as for selector, + with the following change: + Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest ) + + + + + + + + + + + + + + + + + + + + + + + + + + + The three kinds of identity constraints, all with + type of or derived from 'keybase'. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A utility type, not for public use + + A public identifier, per ISO 8879 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + notations for use within XML Schema schemas + + + + + + + + + Not the real urType, but as close an approximation as we can + get in the XML representation + + + + + + + + + + First the built-in primitive datatypes. These definitions are for + information only, the real built-in definitions are magic. + + + + For each built-in datatype in this schema (both primitive and + derived) can be uniquely addressed via a URI constructed + as follows: + 1) the base URI is the URI of the XML Schema namespace + 2) the fragment identifier is the name of the datatype + + For example, to address the int datatype, the URI is: + + http://www.w3.org/2001/XMLSchema#int + + Additionally, each facet definition element can be uniquely + addressed via a URI constructed as follows: + 1) the base URI is the URI of the XML Schema namespace + 2) the fragment identifier is the name of the facet + + For example, to address the maxInclusive facet, the URI is: + + http://www.w3.org/2001/XMLSchema#maxInclusive + + Additionally, each facet usage in a built-in datatype definition + can be uniquely addressed via a URI constructed as follows: + 1) the base URI is the URI of the XML Schema namespace + 2) the fragment identifier is the name of the datatype, followed + by a period (".") followed by the name of the facet + + For example, to address the usage of the maxInclusive facet in + the definition of int, the URI is: + + http://www.w3.org/2001/XMLSchema#int.maxInclusive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NOTATION cannot be used directly in a schema; rather a type + must be derived from it by specifying at least one enumeration + facet whose value is the name of a NOTATION declared in the + schema. + + + + + + + + + + Now the derived primitive types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pattern specifies the content of section 2.12 of XML 1.0e2 + and RFC 3066 (Revised version of RFC 1766). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pattern matches production 7 from the XML spec + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pattern matches production 5 from the XML spec + + + + + + + + + + + + + + + pattern matches production 4 from the Namespaces in XML spec + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A utility type, not for public use + + + + + + + + + + + + + + + + + + + + + + #all or (possibly empty) subset of {restriction, union, list} + + + A utility type, not for public use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Can be restricted to required or forbidden + + + + + + + + + + + + + + + + + + Required at the top level + + + + + + + + + + + + + + + + + + + Forbidden when nested + + + + + + + + + + + + + + + + + + + We should use a substitution group for facets, but + that's ruled out because it would allow users to + add their own, which we're not ready for yet. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + base attribute and simpleType child are mutually + exclusive, but one or other is required + + + + + + + + + + + + + + + + itemType attribute and simpleType child are mutually + exclusive, but one or other is required + + + + + + + + + + + + + + + + + + memberTypes attribute must be non-empty or there must be + at least one simpleType child + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +