Package com.hp.gloze.www_w3_org_2001_XMLSchema

Source Code of com.hp.gloze.www_w3_org_2001_XMLSchema.schema

/*
*  (c) Copyright Hewlett-Packard Company 2001 - 2009
*  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
*    derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
  * @author steven.a.battle@googlemail.com
  */

package com.hp.gloze.www_w3_org_2001_XMLSchema;

import java.beans.IntrospectionException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import com.hp.gloze.Context;
import com.hp.gloze.Gloze;
import com.hp.gloze.XMLBean;
import com.hp.hpl.jena.datatypes.RDFDatatype;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.Ontology;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFList;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.RDFWriter;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Seq;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.jena.vocabulary.XSD;
import com.ibm.icu.util.StringTokenizer;

/*! \page components Schema Components
  
   Gloze will process the following schema components. Excluded components are xs:field, xs:key, xs:keyref, xs:unique
   which enable XML content to be identified by XPath expressions.
  
   - \subpage all "all"
   - \subpage annotation "annotation"
   - \subpage any "any"
  - \subpage anyAttribute "anyAttribute"
   - \subpage attribute "attribute"
   - \subpage attributeGroup "attributeGroup"
  
   - \subpage choice "choice"
   - \subpage complexContent "complexContent"
   - \subpage complexType "complexType"
  
   - \subpage documentation "documentation" 
  
   - \subpage element "element" 
   - \subpage enumeration "enumeration" 
   - \subpage extension "extension"

   - \subpage fractionDigits "fractionDigits"

   - \subpage group "group"

   - \subpage import "import"
   - \subpage include "include"

   - \subpage length "length"
   - \subpage list "list"
  
   - \subpage maxExclusive "maxExclusive"
   - \subpage maxInclusive "maxInclusive"
   - \subpage maxLength "maxLength"
   - \subpage minExclusive "minExclusive"
   - \subpage minInclusive "minInclusive"
   - \subpage maxLength "maxLength"

   - \subpage pattern "pattern"

   - \subpage redefine "redefine"
   - \subpage restriction "restriction"
    
   - \subpage sequence "sequence"
   - \subpage simpleContent "simpleContent"
   - \subpage simpleType "simpleType"
  
   - \subpage totalDigits "totalDigits"
  
   - \subpage union "union"
  
   - \subpage whiteSpace "whiteSpace"

*/

/*! \page schemaLocation xsi:schemaLocation

The XML Schema Instance namespace defines two attributes that declare schema location hints
that can be used by an XML processor to locate the schema.

Gloze may be be supplied with user-defined namespace/schema-location hints (from the command line
or through the API), or it looks for xsi:schemaLocation or xsi:noNamespaceSchemaLocation on the
document element.

The following simple XML may be lifted into RDF either by supplying the schema location
on the command line (eg. "schemaLocation.xml http://example.org/ mySchema.xsd"), or as shown in this case,
using an explicit xsi:schemaLocation. Note that the xsi namespace must be declared.

\include schemaLocation.xml

When dropping a document into XML, a schema location can be added by supplying the full (base) path of the
schema using the schemaLocation parameter (e.g. "-Dgloze.schemaLocation=file:/C:/myExamples/mySchema.xsd" ).
The schema used in the mapping are relativized against this base and added to the xsi:schemaLocation or
xsi:noNamespaceSchemaLocation attribute on the document element.
*/


public class schema extends XMLBean {

  public static final String XSD_URI = "http://www.w3.org/2001/XMLSchema";
  public static final String XSI = "http://www.w3.org/2001/XMLSchema-instance";
   
  public static final String anySimpleType = XSD_URI+"#anySimpleType";
  public static final String anyType = XSD_URI+"#anyType";
  public static final String ENTITY = XSD_URI+"#ENTITY";
  public static final String ID = XSD_URI+"#ID";
  public static final String NOTATION = XSD_URI+"#NOTATION";
 
  // targetNamespace is reserved for the actual value set in the schema
  // namespace is the working copy and may be set to a default if no tns is provided
 
  private String version, targetNamespace, //namespace,
    elementFormDefault = "unqualified",
    attributeFormDefault = "unqualified",
    blockDefault = "", finalDefault = "";

  private Import[] _import;
  private Include[] include;
  private element[] element;
  private complexType[] complexType;
  private simpleType[] simpleType;
  private attribute[] attribute;
  private attributeGroup[] attributeGroup;
  private group[] group;
  private redefine[] redefine;
  private annotation[] annotation;
 
  // the schema location
  public URL _url;
  public OntModel ont; // the ontology for this schema
  private boolean processed = false;
 
  public enum type {
    complexType, simpleType
  }
 
  public schema() throws IntrospectionException {
    ont = ModelFactory.createOntologyModel();
  }

  public boolean isDefault(String attribute, String value) {
    if (attribute.equals("elementFormDefault"))
      return value.equals("unqualified");
    if (attribute.equals("attributeFormDefault"))
      return value.equals("unqualified");
    if (attribute.equals("blockDefault"))
      return value.equals("");
    if (attribute.equals("finalDefault"))
      return value.equals("");
    return false;
  }
 
  /** unqualified names are defined in the target namespace (or supplied namespace if undefined)
   * qualified names require prefix expansion using schema xmlns declarations */
 
  public String expandName(String name, Model model, Context ctx) {
    if (getTargetNamespace()!=null)
      return qualifiedName(name,null,model);
    else return unqualifiedName(name,null,model,ctx);
  }
 
  /** name an qualified component in the target namespace */

  protected String qualifiedName(String name, String symbol, Model model) {
    return concatName(getTargetNamespace(), symbol, name);
  }
 
  /** name an unqualified component in the given namespace */

  protected String unqualifiedName(String name, String symbol, Model model, Context ctx) {
    String ns = ctx.getDefaultNS();
    if (ns==null) ns=Context.DEFAULT_XMLNS; // use xs URL where unqualified is undefined
    return concatName(ns, symbol, name);
  }

  /** add globals to the context, maintaining a set of explored schema */
 
  public void gatherGlobals(Model model, Context ctx, Set<URL> done) {
    Set<String> globalElements = new HashSet<String>();
    Set<String> globalAttributes = new HashSet<String>();
    Set<String> globalTypes = new HashSet<String>();
    Set<String> localElements = new HashSet<String>();
    Set<String> localAttributes = new HashSet<String>();
   
    // we're done with this URL (don't explore it again)
    done.add(get_url());
   
    // consult included schema
    for (int i = 0; include != null && i < include.length; i++)
      include[i].gatherGlobals(model,ctx, done);
   
    // consult imported schema
    for (int i = 0; _import != null && i < _import.length; i++)
      _import[i].gatherGlobals(model,ctx, done);

    // consult redefined schema
    for (int i = 0; redefine != null && i < redefine.length; i++)
      redefine[i].gatherGlobals(model, ctx, done);   

    if (ctx.isReport()) System.out.println("REPORT "+get_url());

    // global elements
    if (ctx.isReport()) System.out.println("GLOBAL ELEMENTS");
    for (int i = 0; element!=null && i < element.length; i++) {
      String uri = element[i].createURI(model,ctx);
      ctx.putElement(uri,element[i]);
      globalElements.add(uri);
      if (ctx.isReport()) System.out.println("\t"+uri);
     
      // ..and substitution groups
      String sub = element[i].getSubstitutionGroup();
      if (sub!=null) ctx.putSubstitution(element[i], element[i].createURI(model,sub,ctx));
    }

    // global attributes
    if (ctx.isReport()) System.out.println("GLOBAL ATTRIBUTES");   
    for (int i = 0; attribute!=null && i < attribute.length; i++) {
      String uri = attribute[i].createURI(model,ctx);
      ctx.putAttribute(uri,attribute[i]);
      globalAttributes.add(uri);
      if (ctx.isReport()) System.out.println("\t"+uri);
    }
    // global groups
    for (int i = 0; group!=null && i < group.length; i++) {
      ctx.putGroup(group[i].createURI(model,ctx),group[i]);
    }   
    // global attribute groups
    for (int i = 0; attributeGroup!=null && i < attributeGroup.length; i++) {
      ctx.putAttributeGroup(attributeGroup[i].createURI(model,ctx),attributeGroup[i]);
    }   
    // global simple type
    for (int i = 0; simpleType!=null && i < simpleType.length; i++) {
      ctx.putSimpleType(simpleType[i].createURI(model,ctx),simpleType[i]);
    }   
    // global complex type
    if (ctx.isReport()) System.out.println("GLOBAL TYPES");   
    for (int i = 0; complexType!=null && i < complexType.length; i++) {
      String uri = complexType[i].createURI(model,ctx);
      globalTypes.add(uri);
      ctx.putComplexType(uri,complexType[i]);
      if (ctx.isReport()) System.out.println("\t"+uri);
    }
   
    reportLocalElements(model,localElements,ctx);
    reportLocalAttributes(model,localAttributes,ctx);
    if (ctx.isReport()) {
      System.out.println("LOCAL ELEMENTS");
      for (String uri: localElements) System.out.println("\t"+uri);
      System.out.println("LOCAL ATTRIBUTES");
      for (String uri: localAttributes) System.out.println("\t"+uri);
      System.out.println();
    }
   
    // check for name clashes
    clash(globalElements, globalAttributes);
    clash(globalElements, globalTypes);
    clash(globalElements, localAttributes);
    clash(globalElements, localElements);
   
    clash(globalAttributes, globalTypes);
    clash(globalAttributes, localElements);
    clash(globalAttributes, localAttributes);

    clash(globalTypes, localElements);
    clash(globalTypes, localAttributes);
   
    clash(localAttributes, localElements);
}
 
  void clash(Set<String> s, Set<String> t) {
    for (String m: s) if (t.contains(m)) Gloze.logger.warn("uri clash: "+m);
  }
 
  static int textToRDF(Resource subject, Seq seq, Node node, int index, Context ctx) {
    NodeList l = node.getChildNodes();
    next: while (index < l.getLength()) {
      Node n = l.item(index);
      switch (n.getNodeType()) {
      case Node.TEXT_NODE:
        textToRDF(subject, seq, n, ctx);
      case Node.COMMENT_NODE:
        index++;
        break;
      case Node.ELEMENT_NODE:
        break next;
      }
    }
    return index;
  }
 
  public static void textToRDF(Resource subject, Seq seq, Node n, Context ctx) {
    String value = ((Text) n).getNodeValue();
    value = processWhitespace(n,value,null,ctx);
    if (!value.equals("")) {
      Model m = ctx.getModel();
      Literal lit = m.createLiteral(value);
      Statement stmt = m.createStatement(subject, RDF.value, lit);
      m.add(stmt);
      if (seq!=null) seq.add(stmt.createReifiedStatement());
    }
  }
 
  /*! \page noSchemaMapping No-Schema Mapping
   The use of xs:any makes it necessary to map content for which we have no schema.
  
   - \ref any "any example"
  
   The schema-less mapping can be used even where we have no schema at all
   (this is the default mode if no match can be found for the document element).
  
   See also the use of xsi:type for returning from a No-Schema mapping back into a schema.
   - \ref type
   */
 
  public boolean toRDF(Resource subject, Property prop, String value, String type, Element elem, Context ctx)
  throws Exception {
    if (elem.hasAttribute("xml:lang")) {
      // no datatype required for a lang qualified string
      Literal l = ctx.getModel().createLiteral(value,elem.getAttribute("xml:lang"));
      subject.addProperty(prop,l);
      return true;
    }
    return toRDF(elem, subject, prop, processWhitespace(elem,value,type,ctx), type, null, null, ctx);
  }
 
  /*! \page datatypes Datatypes
  
   The RDF semantics recommendation identifies a subset of XML schema datatypes that are suitable for use in RDF.
   The following XML datatypes may be used in RDF typed literals.
   For example, an xs:string "foobar", would be represented in RDF (N3)
   as "foobar"^^<http://www.w3.org/2001/XMLSchema#string>.
   
     - xs:string
     - xs:boolean
     - xs:decimal
     - xs:float
     - xs:double
     - xs:dateTime
     - xs:time
     - xs:date
     - xs:gYearMonth
     - xs:gYear
     - xs:gMonthDay
     - xs:gDay
     - xs:gMonth
     - xs:hexBinary
     - xs:base64Binary
     - xs:anyURI
     - xs:normalizedString
     - xs:token
     - xs:language
     - xs:NMTOKEN
     - xs:Name
     - xs:NCName
     - xs:integer
     - xs:nonPositiveInteger
     - xs:negativeInteger
     - xs:long
     - xs:int
     - xs:short
     - xs:byte
     - xs:nonNegativeInteger
     - xs:unsignedLong
     - xs:unsignedInt
     - xs:unsignedShort
     - xs:unsignedByte
     - xs:positiveInteger 
 
  \subpage elementString "datatype example"
  
   The exceptions include:
   - xs:anySimpleType
   - xs:duration
   - xs:ENTITY
   - xs:ENTITIES
   - xs:ID
   - xs:IDREF
   - xs:IDREFS
   - xs:NMTOKENS
   - xs:NOTATION
   - xs:QName
  
   \see
   http://www.w3.org/TR/2004/REC-rdf-mt-20040210/
   http://www.w3.org/TR/xpath-functions/
   http://www.w3.org/TR/swbp-xsch-datatypes/
  
   The following sections explore work-arounds for all of these datatypes.
  
   \section anySimpleType The mother of all simple types (xs:anySimpleType)
  
   This type is the base of all simple types with an unconstrained lexical space. User defined restrictions of
   xs:anySimpleType are not allowed. Indeed, users are generally advised to steer clear of it altogether.
  
   Yet, both elements and attributes may be defined to be of type xs:anySimpleType (it's also the default type for attributes).
   Also, anySimpleType may be used as the base of a simpleContent extension.
  
   Thinking about an RDF savvy mapping, it occupies a similar place in the pantheon of classes
   as rdfs:Literal, the superclass of all literals including datatypes.
   Thus any XML content of type xs:anySimpleType is mapped to an rdfs:Literal.

   \subpage attributeAnySimpleType "anySimpleType example"

   \see 
   http://www.w3.org/2001/05/xmlschema-rec-comments#pfiS4SanySimpleType
   http://lists.w3.org/Archives/Member/w3c-xml-schema-ig/2002Jan/0065.html

   \section duration Duration (xs:duration)
  
   The problem with xs:duration is that there's no well-defined total ordering over it's value space
   (durations are partially ordered).
   The problem stems from there being an indeterminate number of days in a month.
   The recommended solution used by Gloze is to
   distill a single period such as "P7Y2M26DT14H18M10S" (years, months, days, hours, minutes, seconds)
   into separate xs:yearMonthDuration "P7Y2M" (years, months) and xs:dayTimeDuration "P26DT14H18M10S" (days, hours, minutes, seconds) datatypes.
   The reverse process, is equivalent to adding the these values, both of which are subclasses of duration.
   When adding two durations, each component is added independently, ignoring - in particular - any carry from days to months.
  
   \subpage elementDuration "duration example"
  
   \section entity Entities (xs:ENTITY)
  
   An XML schema ENTITY allows the substitution of common text values or balanced mark-up defined as XML entities.
   ENTITY values must match an entity name declared in the DTD of the instance document.
   The value space of unexpanded entities is scoped to the instance document it appears in.
   For the XML to RDF mapping, internally defined entities are therefore expanded.
   As they may include balanced mark-up, an expanded entity can be described as an RDF XMLLiteral.
   There is currently no reverse mapping due to technical issues in editing document type declarations in level 2 DOM.
  
   \subpage elementENTITY "entity example"
     
   \see http://jena.sourceforge.net/how-to/typedLiterals.html#xsd
  
   \section xsid Identity datatypes (xs:ID, xs:IDREF)
  
    An element is considered to have an ID if it has an attribute of type ID, or if the type of the element itself is an ID.
   
    IDs have no distinguishing features looking at the XML alone, they look like ordinary content.
    We look to the XML schema which will identify the datatype as xml schema ID.
    The ID is associated with the enclosing element, and that element can have at most one ID.
   
    XML IDs are defined to have document scope, such that a given ID must be unique within a single document
    and that each ID reference should have a corresponding ID within the same document.
    One advantage of the mapping into RDF is that a single RDF model may contain descriptions
    of multiple documents. We have ensure that we preserve the global uniqueness of identifiers,
    and do not lose the correlation between IDs and their references when moving to this global context.
    An identifier of type ID can be transformed into a URI by treating it as a fragment identifier relative to the document base.
   
    For example, a base <tt>http://example.org/base</tt> an XML ID "foobar" combine to give the URI,
    <tt>http://example.org/base#foobar</tt> .
   
    Properties of type ID will disappear, as these simply define the URI of the identified resource.
    A corresponding reference to this resource with an IDREF is similarly expanded into a URI reference.
   
   \subpage elementIdentity "identity example"
  
   \section notation Notation (xs:NOTATION)
  
   NOTATIONs are restricted to QNames declared in the schema. For the purposes of RDF mapping they are subject to the same rules as QNames.
   The target namespace and notation name are expanded to give an absolute URI for the notation resource.
  
   \subpage attributeNotation "notation example"
       
   \section qNames Qualified Names (xs:QName)
  
   QNames define the space of (optionally) qualified local names. The scope of an XML namespace prefix includes the
   element it is defined in and its children (subject to shadowing). This lexical scoping doesn't translate directly into RDF where everything has global scope.
   However, the expanded QName is a URI, so it may be translated into an object reference, though typically we have no knowledge of the type of object referred to.
   This URI becomes associated with a resource.
  
   For example, given a namespace prefix 'eg' defined as "http://example.org" the QName "eg:foobar" would be
   expanded to give the URI, <tt>http://example.org#foobar</tt> .
  
   \subpage elementQName "QName example"
  
   \section listTypes List types (xs:IDREFS, xs:ENTITIES, xs:NMTOKENS)
  
   Although list types are treated as simple in XML schema, they are not recommended for use in RDF. Instead,
   we construct an rdf:list of the corresponding non-list type (xs:IDREF, xs:ENTITY, xs:NMTOKEN).
  
   \subpage elementIDREFS "IDREFS example"

  */

  /*! \page subclass SubClass Relationships (complex type derivation)
  
   Sub-class relationships may be derived from extensions and restrictions of complex content.
  
   - \ref restrictionComplexContent "restriction of complex content"
   - \ref extensionComplexContent "extension of complex content"
  
   */

  public boolean toRDF(Node node, Resource subject, Property prop, String value, String type, Seq seq, Set<restriction> restrictions, Context ctx)
  throws Exception {
   
    if (type!=null && type.equals(XSD_URI+"#anySimpleType")) type = RDFS.Literal.getURI();
     
    RDFDatatype dt = getDatatype(type);
    Model m = ctx.getModel();
    Statement stmt = null;
    RDFNode object = null;
    if (value==null) return true;

    // are all restrictions observed
    if (restrictions!=null)
      for (restriction r: restrictions)
        if (!r.isValid(value,type,ctx)) return false;
   
    simpleType s = ctx.getSimpleType(type);
    if (s!=null) return s.toRDF(subject,prop,node,value,seq,restrictions,ctx);
   
    // this may be an ID embedded in element content
    else if (type!=null && type.equals(XSD_URI+"#ID")) {
      String uri = subject.isAnon()?null:subject.getURI();
      String frag = addFragment(ctx.getBaseMap(), value).toString();
      if (frag.equals(uri)) return true;
      else object = m.createResource(frag)
    }   
    else if (type!=null && type.equals(XSD_URI+"#IDREF"))
      object = m.createResource(addFragment(ctx.getBaseMap(), value).toString());   
   
    else if (type!=null && type.equals(XSD_URI+"#IDREFS"))
      object = toRDFList(node,value,XSD.IDREF.getURI(),null,ctx);   

    else if (type!=null && type.equals(XSD_URI+"#ENTITIES"))
      object = toRDFList(node,value,XSD.ENTITY.getURI(),null,ctx);   

    else if (type!=null && (type.equals(XSD_URI+"#QName") || type.equals(XSD_URI+"#NOTATION")))
      object = m.createResource(expandQName(ctx.getDefaultNS(),value,node,ctx.getModel()));
   
    else if (type!=null && type.equals(XSD_URI+"#anyURI")) {
      URI uri = null;
      if (isValidURI(value)) uri = new URI(value);
      // it may be a relative URI
      // to avoid confusion it should begin with an initial name character
      // ensure it isn't a QName
      else if (value.indexOf(":")<0 && Character.isJavaIdentifierStart(value.charAt(0)))
        uri = resolveBase(node, new URI(value), ctx);   
      if (uri!=null) object = m.createTypedLiteral(uri.toString(),dt);
      else return false;
    }
    else if (type!=null && type.equals(XSD_URI+"#anySimpleType")) {
      object = m.createTypedLiteral(value==null?"":value,dt);
    }
    else if (RDFS.Literal.getURI().equals(type)) {
      object = m.createLiteral(value==null?"":value);
    }
    else if (value!=null && dt!=null && dt.isValid(value)) object = m.createTypedLiteral(value, dt);
    else object = m.createLiteral(value==null?"":value);
   
    if (object==null) return false;
    // if no property is supplied just add the value to the sequence/list
    if (prop==null && seq!=null) seq.add(object);
    else  {
      stmt = m.createStatement(subject, prop, object);
      m.add(stmt);
      // this can only be a sequence
      if (seq != null) seq.add(stmt.createReifiedStatement());     
    }   
    return true;   
  }
 
  /*! \page order Ordered Content
  
   An XML document has a tree structure where the children of each element are lexically ordered.
   Sometimes this ordering is significant, sometimes it is not. Gloze is designed from the point of
   view of retaining sufficient information to reconstruct the original document from the RDF, making it
   possible to round-trip from XML to RDF and back again. This doesn't mean recording the
   order in all cases. In many cases the XML schema contains enough ordering information to
   reconstruct the original sequence. Ambiguity is created by multiple occurrences of the same element,
   by mixed content, or by the appearance of the xs:any wild-card. Sequences of singly occurring
   xs:sequence are entirely unambigous, as are choices where only one of the choices can occur
   (so long as this occurs once). The compositor 'all', where all orderings are valid typically require
   sequencing (unless in the degenerate case where they only have a single element).
   The ordering of attributes is not significant.
  
   All the examples in this section were generated with order=seq (-Dgloze.order=seq).
  
   The following schema describes an unambiguous sequence containing an unambiguous choice.
  
   \include ordering.xsd
  
   The XML below requires no additional ordering information.
  
   \include ordering.xml
   \include ordering.n3
  
   Where there is ambiguity in the schema for a given element content this is captured as an RDF sequence.
   We need to record the order in which particular statements appear. This is achieved by
   reifying the statement, giving us an object that can be added to an rdf:Seq.
  
   The schema below permits multiple occurrences of the element 'bar', so ordering information needs
   to be recorded if it is significant.
  
   \include ordering1.xsd
   \include ordering1.xml
  
   The RDF mapping shows how ordering information is recorded alongside the standard RDF mapping.
   The standard mapping involves adding the property 'foo' with value "foobar".
   The subject of this statement is also an RDF sequence, and the first member of this
   sequence is the reification with rdf:predicate 'foo' and rdf:object "foobar".
   The two occurrences of 'bar'with identical values, "foobar" result in the assertion
   of a single property/value. Despite this, two reified statements are added to the sequence,
   one for each occurrence.
  
   \include ordering1.n3
  
   Ordering is transparent from an ontological perspective. One of the design goals was
   to allow users of the RDF mapping to ignore the sequence if it is not relevant.
   Ordering is treated as a data-structuring issue rather than an ontological one.
   The addition of a property to a resource is treated independently of adding it to the sequence;
   sequencing meta-data is overlaid on top of the existing unordered information model.
  
   */
  
  /*! \page mixed Mixed Content
  
   Mixed content, that is text interleaved with markup, also requires ordering. The following example
   includes combined text and markup. Note that the text content of an element appears as an rdf:value.
  
   \include mix.xml
   \include mix.xsd
   \include mix.n3
  */

  /*! \page identity Identity
   XML is not just a tree, but a tree with pointers.
   An xs:IDREF points to an element with an xs:ID within the same document.
   An xs:ID identifies the immediately containing element. Typically this is an
   xs:ID attribute on the element, though it may also be xs:ID simple content.
  
   In RDF we identify the element \em content, by assigning it a URI.
   This URI is the object of the statement representing the element occurrence.
  
   - \subpage attributeID "attribute identity"
   - \subpage elementID "element identity"
  
   */
 
  /*! \page type xsi:type
   The XML schema instance namespace defines xsi:type allowing elements be be explicitly annotated with
   type information. This can be used as an alternative mechanism to substitution groups, but also provides
   a way to jump back into a schema from within xs:any content. An example of this is shown below using an XML
   document that has no schema.
  
   The document element 'myLink' is not defined in the schema, so is processed as if it were subject to xs:any
   and a default no-schema mapping is employed.
   This unidentified element is treated as unqualified and is defined in the default namespace set by the xmlns parameter.
  
   The link schema doesn't define the 'myLink' element, but it does define the 'SimpleLink' content. The XML
   instance refers to this using an xsi:type attribute. The RDF mapping for this generates a corresponding rdf:type
   statement. The content of 'myLink' is then processed according to the content model of 'SimpleLink', so we have
   escaped from the xs:any no-schema mapping.

   \include linkType.xml  
   \include linkType.xsd
  
   The use of the 'SimpleLink' content model is evidenced by the correct datatyping of the xlink:href and the
   insertion of the xlink:type implied by the xlink attribute group.
  
   \include linkType.n3
  
   \see http://www.w3.org/2001/XMLSchema-instance
   */
 
  static Statement toRDFStatement(Resource subject, Element elem, Property prop, String value, String type, Context ctx)
  throws Exception {
    Model m = ctx.getModel();

    if (value==null) {
      if (prop==RDF.value || type.endsWith("#ID")) return null;
      return m.createStatement(subject,prop,"");
    }
   
    Statement stmt = null;
    if (type.endsWith("#ID")) ;
    // ID is used to name the owning element - don't generate RDF
    // IDREF to globally named element
    else if (type.endsWith("#IDREF")) {
      Resource r = m.createResource(addFragment(ctx.getBaseMap(), value).toString());
      stmt = m.createStatement(subject,prop,r);
    }
    else if (type.endsWith("#IDREFS")) {
      Resource r = toRDFList(elem,value,XSD.IDREF.getURI(),null,ctx)
      stmt = m.createStatement(subject,prop,r);
    }
    else if (type.endsWith("#NMTOKENS")) {
      Resource r = toRDFList(elem,value,XSD.NMTOKEN.getURI(),null,ctx)
      stmt = m.createStatement(subject,prop,r);
    }
    else if (type.endsWith("#QName")) {
      RDFNode object = null;
      String name = XMLBean.expandQName(ctx.getDefaultNS(),null,value,elem,ctx.getModel());
      if (name!=null) {
        object = m.createResource(name);
        stmt = m.createStatement(subject,prop,object);
      }
    }
    else if (type.endsWith("#duration")) {
      // map duration into separate xs:yearMonthDuration and xs:dayTimeDuration
      // introduce intermediate bnode
      Resource object = m.createResource();
      stmt = m.createStatement(subject,prop,object);
      RDFNode ym = schema.yearMonthDuration(m,value);
      RDFNode dt = schema.dayTimeDuration(m,value);
      if (ym!=null) object.addProperty(RDF.value, ym);
      if (dt!=null) object.addProperty(RDF.value, dt);
    }
    else if (type.endsWith("#ENTITY")) {
      DocumentType doctype = elem.getOwnerDocument().getDoctype();
      Pattern entityPattern = Pattern.compile("<!ENTITY\\s+"+value+"\\s+'(.*)'>");
      Matcher match = entityPattern.matcher(doctype.getInternalSubset());
      if (match.find()) value = match.group(1);
      Literal l = m.createTypedLiteral(value,RDF.getURI()+"XMLLiteral");
      stmt = m.createStatement(subject,prop,l);
    }
    else { // schema datatype?
      RDFDatatype dt = getDatatype(type);
      if (dt != null) {
        Literal l = m.createTypedLiteral(processWhitespace(elem,value,type,ctx), dt);
        stmt = m.createStatement(subject,prop,l);
      }
    }
    return stmt;
  }
 
  static String processWhitespace(Node node, String value, String type, Context ctx) {
    if (value==null) return null;
    // whitespace processing is a two-step process involving whitespace replacement and collapse
    boolean replace = true, collapse = true;
   
    // get xml:space setting for this node
    boolean preserve = preserved(node,ctx.isPreserved());
   
    // don't process text (unless overridden)
    if (type==null) replace = collapse = !preserve;
   
    // don't process strings (unless overridden)
    else if (type.equals(schema.XSD_URI+"#string"))
      replace = collapse = false;
       
    // only perform whitespace replacement on normalized strings (unless overridden)
    else if (type.equals(schema.XSD_URI+"#normalizedString"))
      collapse = false; // replace whitespace only
   
    if (replace) value = replaceWhitespace(value);
    if (collapse) value = collapseWhitespace(value);
    return value;
  }
 
  /** whitespace replacement */
  static String replaceWhitespace(String value) {
    if (value!=null) return value.
    replaceAll("\t", " ").
    replaceAll("\r", " ").
    replaceAll("\f", " ").
    replaceAll("\n", " ");
    return value;
  }
 
  /** whitespace collapse */
  static String collapseWhitespace(String value) {
    if (value!=null) {
      value = value.trim();
      while (value.indexOf("  ")>0) value = value.replaceAll("  "," ");
    }
    return value;
  }
 
  static boolean preserved(Node node, boolean def) {
    if (node==null) return def;
    switch (node.getNodeType()) {
    case Node.ATTRIBUTE_NODE:
      Attr a = (Attr) node;
      if (a.getNamespaceURI()!=null && a.getNamespaceURI().equals(XML) && a.getLocalName().equals("space"))
        return a.getValue().equals("preserve");
      return preserved(a.getOwnerElement(),def);
    case Node.ELEMENT_NODE:
      Element e = (Element) node;
      if (e.hasAttributeNS(XML,"space"))
        return e.getAttributeNS(XML,"space").equals("preserve");
      return preserved(e.getParentNode(),def);
    default:
      return def;
    }
  }
 
  /** map an array of attributes to RDF */
 
  public void toRDF(Resource subject, Node node, attribute[] attribute, Context ctx)
  throws Exception {
    Model m = subject.getModel();
    NamedNodeMap atts = node.getAttributes();
    // expand attribute names
    Map<String,Node> map = new HashMap<String,Node>();
    for (int i=0; i<atts.getLength(); i++) {
      // xmlns declaration
      if (atts.item(i).getNodeName().startsWith("xmlns")) {
        // set the namespace definition on the model
        String name = atts.item(i).getNodeName();
        String prefix = "";
        if (name.indexOf(":")>=0) {
          prefix = name.substring("xmlns:".length());
          String ns = atts.item(i).getNodeValue();
          if (!ns.equals(XMLBean.XML) && !ns.equals(schema.XSI))
            addPrefixes(prefix,ns,m);
        }
        continue;
      }
      else {
        String name = expandQName((Attr) atts.item(i),ctx);
        // The XML namespace is disallowed in RDF
        if (!name.startsWith(XMLBean.XML)) map.put(name,atts.item(i));
      }
    }   
    for (int i = 0; attribute != null && i < attribute.length; i++) {
      attribute def = attribute[i].getDefinition(m,ctx);
      if (def==null) {
        if (!attribute[i].getRef().startsWith("xml:"))
          Gloze.logger.warn("undefined attribute: "+attribute[i].getRef());
        continue;
      }     
      Attr a = (Attr) map.get(def.createURI(m,ctx)); //map.getNamedItem(name);
      // the attribute may not have any occurrences
      attribute[i].toRDF(subject, a, ctx);
    }   
  }
 
  /** map a list type to an RDF list, e.g. IDREFS (list of IDREF) */

  public static RDFList toRDFList(Node node, String values, String itemType, Set<restriction> restrictions, Context ctx)
  throws Exception {
    if (values==null) return null;
    RDFList l= ctx.getModel().createList();
    StringTokenizer t = new StringTokenizer(values);
    while (l!=null && t.hasMoreTokens())
      l = toRDFList(node,t.nextToken(),itemType,l,restrictions,ctx);
    return l;
  }
 
  /** incrementally add a value to an RDFList */
 
  public static RDFList toRDFList(Node node, String value, String itemType, RDFList list, Set<restriction> restrictions, Context ctx)
  throws Exception {
    RDFDatatype dt = getDatatype(itemType);
    Model m = ctx.getModel();
    RDFNode object = null;
   
    value = processWhitespace(node,value,itemType,ctx);

    if (itemType!=null && itemType.equals(XSD_URI+"#QName")) {
      String name = expandQName(ctx.getDefaultNS(),null,value,node,ctx.getModel());
      if (name==null) return null; // one bad value invalidates the entire list
      else object = m.createResource(name);
    }
    else if (itemType!=null && itemType.equals(XSD.IDREF.getURI())) {
      if (value.indexOf(':')>=0) return null; // avoid confusion with QNames
      object = ctx.getModel().createResource(addFragment(ctx.getBaseMap(), value).toString());
    }
   
    else if (itemType!=null && itemType.equals(XSD_URI+"#anyURI")) {
      URI uri = null;
      if (isValidURI(value)) uri = new URI(value);
      // ensure this isn't a QName
      else if (value.indexOf(":")<0 && Character.isJavaIdentifierStart(value.charAt(0)))
        uri = resolveBase(node, new URI(value), ctx);
      if (uri!=null) object = m.createTypedLiteral(uri.toString(),dt);
      else return null;
    }
    else if (value!=null && dt!=null && dt.isValid(value)) object = m.createTypedLiteral(value, dt);
    else object = m.createLiteral(value==null?"":value);
   
    // add the value to the list
    if (list.isEmpty()) list = ctx.getModel().createList(new RDFNode[] {object});
    else list.add(object);
    return list;   
  }

  public static URI resolveBase(Node node, URI uri, Context ctx) {
    // get base from instance document
    while (node!=null && node.getNodeType()!=Node.DOCUMENT_NODE) {
      String base = node.getBaseURI();
      if (base!=null) try {
        uri = new URI(base).resolve(uri);
        if (uri.toString().startsWith("http://")) return uri;
      } catch (URISyntaxException e) {
        Gloze.logger.warn("bad base: "+base);
      }
      node = node instanceof Attr?((Attr) node).getOwnerElement():node.getParentNode();
    }
    // default base setting?
    return ctx.getBaseMap().resolve(uri);
  }
   
  // convert a datatyped value into an XML text value
 
  public boolean toXMLText(Element element, RDFNode rdf, String type, String pack, Context ctx) {
    String v;
    Document doc = element.getOwnerDocument();
   
    simpleType s = ctx.getSimpleType(type);
    if (s!=null) return s.toXML(element,rdf,pack,ctx);

    if (type!=null && type.equals(XSD_URI+"#IDREFS") && rdf instanceof Resource
        && ((Resource)rdf).hasProperty(RDF.first)
        && rdf.canAs(RDFList.class)) {
      RDFList l = (RDFList) rdf.as(RDFList.class);
      for (ExtendedIterator i=l.iterator(); i.hasNext();) {
        v = toXMLValue(element, (RDFNode) i.next(), XSD.IDREF.getURI(), ctx);
        if (v==null) return false; // failed for this type
        element.appendChild(doc.createTextNode(pack==null?v:pack+v));
        pack = " ";
      }
      return true;
    }
    String val = toXMLValue(element, rdf, type, ctx);
    if (val!=null) {
      element.appendChild(doc.createTextNode(pack==null?val:pack+val));
      return true;
    }
    return false;
  }
 
  public boolean listToXML(Attr attr, RDFList list, String itemType, Context ctx) throws Exception {
    for (ExtendedIterator i=list.iterator(); i.hasNext();) {
      if (!toXML(attr,(RDFNode) i.next(),itemType,ctx)) return false;
    }
    return true;
  }
 
  public String listToString(Resource r, Element elem, String type, Context ctx) {
    String v = null;
    if (r.canAs(RDFList.class)) {
      RDFList l = (RDFList) r.as(RDFList.class);
      for (ExtendedIterator i=l.iterator(); i.hasNext();) {
        String s1 = toXMLValue(elem,(RDFNode) i.next(),type,ctx);
        v = v==null?s1:v+ " "+s1;
      }
    }       
    return v;
  }

  /** convert a datatyped value into an XML attribute value */
 
  public boolean toXML(Attr attr, RDFNode rdf, String type, Context ctx) throws Exception {
    Element e = attr.getOwnerElement();
    String a = attr.getValue();
    String v = toXMLValue(e, rdf, type, ctx);
    if (v!=null) {
      if (a==null || a.equals("")) attr.setValue(v);
      else attr.setValue(a+" "+v);
      return true;
    }
    return false;
  }

  public String toXMLValue(Element elem, RDFNode rdf, String type, Context ctx) {
    String v = null;
    if (rdf instanceof Resource) {
      Resource r = (Resource) rdf;
     
      if (type!=null && (type.equals(XSD_URI+"#QName") || type.equals(XSD_URI+"#NOTATION")) && !r.isAnon())
        v = r.getURI();
      else if (type!=null && type.equals(XSD_URI+"#ID") && !r.isAnon())
        v = r.getLocalName();
      else if (type!=null && type.equals(XSD.IDREF.getURI()) && !r.isAnon()
          && XMLBean.equalNS(r.getNameSpace(),ctx.getBaseMap().toString()))
        v = r.getLocalName();
      else if (type!=null && type.equals(XSD_URI+"#IDREFS")) {
        v = listToString(r,elem,XSD.IDREF.getURI(),ctx);
      }
      else if (type!=null && type.equals(XSD_URI+"#NMTOKENS")) {
        v = listToString(r,elem,XSD.NMTOKEN.getURI(),ctx);
      }
      else if (r.hasProperty(RDF.value)) {
        Statement stmt = r.getProperty(RDF.value);
        if (type!=null && type.equals(XSD_URI+"#IDREF"))
          v = stmt.getResource().getLocalName();
        else if (stmt.getObject() instanceof Literal) v = stmt.getString();   
      }     
      else if (r.canAs(RDFList.class)) {
        v = listToString(r,elem,null,ctx);
      }
    }
    else if (rdf instanceof Literal) {
      v = ((Literal) rdf).getString();
    }
   
    if (type!=null && type.equals(XSD_URI+"#QName"))
      v = contractQName(v, elem, ctx.getModel(), ctx.getBaseMap());
   
    else if (type!=null && (type.equals(XSD_URI+"#anyURI") || type.equals(XSD_URI+"#NOTATION")))
      try {
        v = relativize(ctx.getBaseMap(),new URI(v)).toString();
      } catch (Exception e) {
        // non-fatal
      }
    return v;
  }
 
  // precompiled time patterns
 
  static Pattern durationPattern = Pattern.compile("P((\\d+)Y)?((\\d+)M)?((\\d+)D)?T((\\d+)H)?((\\d+)M)?((\\d+)S)?");
 
  /** map duration into separate dayTimeDuration and yearMonthDuration typed literals */
 
  static RDFNode yearMonthDuration(Model mod, String value) {
    Matcher m = durationPattern.matcher(value);
    if (m.find()) {
      String ym = "P"+
       (m.group(1)!=null?m.group(1):"")+
       (m.group(3)!=null?m.group(3):"");
      // if both components are missing return null
      if (!ym.equals("P"))
        return mod.createTypedLiteral(ym, XSD_URI+"#yearMonthDuration");
    }
    return null;
  }

  static RDFNode dayTimeDuration(Model mod, String value) {
    Matcher m = durationPattern.matcher(value);
    if (m.find()) {
      String dt = "P"+
       (m.group(5)!=null?m.group(5):"")+"T"+
       (m.group(7)!=null?m.group(7):"")+
       (m.group(9)!=null?m.group(9):"")+
       (m.group(11)!=null?m.group(11):"");
      // if all components are missing return null
      if (!dt.equals("P"))
        return mod.createTypedLiteral(dt, XSD_URI+"#dayTimeDuration");
    }
    return null;
  }
 
  /** parse time datatypes into their java counterparts */
 
  public static XMLGregorianCalendar getCalendar(String value) {
    try {
      return DatatypeFactory.newInstance().newXMLGregorianCalendar(value);
    }
    catch (Exception e) {
      return null;
    }   
  }
 

  public static Duration getDuration(String value) {
    try {
      return DatatypeFactory.newInstance().newDuration(value);
    }
    catch (Exception e) {
      return null;
    }
  }

  public static String normalizeString(String value) {
    value = value.replaceAll("\t"," ");
    value = value.replaceAll("\n"," ");
    value = value.replaceAll("\r"," ");
    return value;
  }
 
  // if an owl target file is supplied the output is saved to file
  // if the request is deep map imported and included schema
  // if the target is null and deep then embed the sub-schema
  // pass the schema location relative to the base
 
  public OntModel toOWL(File target, String location, boolean redefinition, Context ctx)
  throws Exception {
    if (processed) return ont;
    // ontology header resource
    Ontology ontology = null;
    if (ctx.getBaseMap()!=null && !redefinition) {
      ontology = ont.getOntology(ctx.getBaseMap().toString()) ;
      if (ontology==null) ontology = ont.createOntology(ctx.getBaseMap().toString());
    }
   
    // add named namespace declarations before anonymous
    // this takes user specified prefix in preference to generated prefix
    declareGlobalNS(ont, ctx);

    // process schema annotation
    for (int i=0; ontology!=null && annotation!=null && i<annotation.length; i++)
      annotation[i].toOWL(ontology,ctx);

    // process included schema
    for (int i=0; include!=null && i<include.length; i++)
      include[i].toOWL(target,location,ctx);

    // process imported schema
    for (int i=0; _import!=null && i<_import.length; i++)
      _import[i].toOWL(target,location,ctx);

    // process redefined schema
    for (int i=0; redefine!=null && i<redefine.length; i++)
      redefine[i].toOWL(ont,target,location,ctx);
   
    if (!ctx.isOverwrite() && target!=null && target.exists()) {
      ont.getDocumentManager().setProcessImports(false);
      Gloze.logger.info("reading "+target.getPath());
      ont.read(new FileInputStream(target), ctx.getBaseMap().toString());

      // sanity check - side-effect adds ont to the global model
      for (ResIterator ri = ont.listSubjectsWithProperty(RDF.type, OWL.Class); ri.hasNext(); )
        ctx.assertOK(ri.nextResource());   
      if (ctx.get_class().equals("intersectionOf"))
        ctx.mergeModel(ont.getBaseModel(), true, new HashMap<RDFNode,RDFNode>());
    }
    else { // create the ontology     
      // global complex types
      for (int i=0; complexType!=null && i<complexType.length; i++)
        complexType[i].toOWL(null,false,ctx);
      // global simple types
      for (int i=0; simpleType!=null && i<simpleType.length; i++)
        simpleType[i].toOWL(ctx);
      // global elements
      for (int i=0; element!=null && i<element.length; i++)
        element[i].toOWL(null,1,1,ctx);
      // global attributes
      for (int i=0; attribute!=null && i<attribute.length; i++)
        attribute[i].toOWL(null,ctx);
      // groups
      for (int i=0; group!=null && i<group.length; i++)
        group[i].toOWL(null,1,1,ctx);
      // attribute groups
      for (int i=0; attributeGroup!=null && i<attributeGroup.length; i++)
        attributeGroup[i].toOWL(null,ctx);
     
      // sanity check - side-effect adds ont to the global model
      //if (ctx.get_class().equals("intersectionOf"))
      ctx.mergeModel(ont.getBaseModel(), true, new HashMap<RDFNode,RDFNode>());

      removeOrphans(ont, OWL.Class);
      removeOrphans(ont, OWL.Restriction);

      // output
     
      // set base
      RDFWriter writer = ont.getWriter(ctx.getLang());
      writer.setProperty("xmlbase", ctx.getBaseMap().toString());
 
      if (target!=null) {
        if (ctx.isVerbose()) Gloze.logger.info("writing "+target.getPath());
        write(ont, writer, target, ctx.getLang(), ctx.getBaseMap().toString());
      }
      else if (!ctx.isSilent()) {
        writer.write(ont.getBaseModel(),System.out, ctx.getBaseMap().toString());
        System.out.println();
      }
    }
   
   
    // save model in the cache in case it is included/imported elsewhere
    ctx.setOntModel(this,ont);
    processed = true;
    return ont;
  }
 
  void removeOrphans(OntModel ont, Resource type) {
    boolean b = true;
    // removing orphans may create orphans
    while (b) {
      b = false;
      // orphaned classes
      for (ResIterator classes = ont.listSubjectsWithProperty(RDF.type,type); classes.hasNext(); ) {
        Resource c = classes.nextResource();
        if (c.isAnon()) {
          // an orphan is anonymous and has no referee other than itself
          Resource r = null;
          Statement s = null;
          for (StmtIterator si = ont.listStatements(null,null,c); si.hasNext(); ) {
            s = si.nextStatement();
            r = s.getSubject();
            if (!r.equals(c)) break;
          }         
          if (r==null || r.equals(c)) {
            b = true;
            c.removeProperties();
          }
        }
      }
    }
  }

  public static void cleanup(Resource type) {
    if (type!=null && !type.isAnon() && type.getURI().startsWith(RDFS.getURI())) return;
    Set<Resource> remove = new HashSet<Resource>();
    for (StmtIterator i = type.listProperties(RDFS.subClassOf); i.hasNext();) {
      Resource r = i.nextStatement().getResource();
      if (r.isAnon()) remove.add(r);
    }     
    for (Resource r: remove) r.removeProperties();
  }

  public void declareGlobalNS(Model model, Context ctx) {
    addPrefix("rdf",RDF.getURI(),model);
    if (_node instanceof Element) {
      NamedNodeMap m = ((Element)_node).getAttributes();
      for (int i=0; i<m.getLength(); i++) {
        Attr a = (Attr) m.item(i);
        if (a.getName().startsWith("xmlns:")) {
          String ns = a.getValue();
          addPrefixes(a.getName().substring("xmlns:".length()),ns,model);
        }
      }   
    }
   
    // add anonymous namespace declaration   
    if (_node instanceof Element) {
      NamedNodeMap m = ((Element)_node).getAttributes();
      for (int i=0; i<m.getLength(); i++) {
        Attr a = (Attr) m.item(i);
        if (a.getName().equals("xmlns")) {
          String ns = a.getValue();
          if (!model.getNsPrefixMap().containsValue(terminateNS(ns)))
            addPrefix(ctx.createNSPrefix(),ns,model);
          break;
        }
      }   
    }

    // user specified default namespace
    String ns  = ctx.getDefaultNS();
    if (ns!=null && !model.getNsPrefixMap().containsValue(terminateNS(ns)))
        addPrefix(ctx.createNSPrefix(),ns,model);
   
    // target namespace
    String tns = getTargetNamespace();
    if (tns!=null && !model.getNsPrefixMap().containsValue(terminateNS(tns)))
      addPrefix(ctx.createNSPrefix(),tns,model);
  }

  private void write(OntModel ont, RDFWriter writer, File target, String lang, String base) throws IOException {
    File dir = target.getCanonicalFile();
    if (!dir.isDirectory()) dir = dir.getParentFile();
    if (!dir.exists()) dir.mkdirs();
    writer.write(ont.getBaseModel(), new FileWriter(target), base);
  }
 
  /** Is this a valid data-type rather than an object type **/
 
  // we allow xs:ID so we can delete related cardinality restrictions
  public static boolean  isValidDatatype(String type) {
    if (type==null) return false;
   
    // All the XSD types below may be object rather than data types
   
    if (type.equals(schema.XSD_URI+"#anyType") ||
      // structured type
      type.equals(schema.XSD_URI+"#duration") ||
      // list type
      type.equals(schema.XSD_URI+"#IDREFS") ||
      type.equals(schema.XSD_URI+"#ENTITIES") ||
      type.equals(schema.XSD_URI+"#NMTOKENS") ||
      // object reference
      type.equals(schema.XSD_URI+"#IDREF") ||
      type.equals(schema.XSD_URI+"#QName") ||
      type.equals(schema.XSD_URI+"#NOTATION")) {
     
      return false;
    }
    else return true;
  }

  /* set ontology property type (inclusively object or datatype) */
   
  public static void defineType(Property prop, String type) {
    if (type==null || type.equals(schema.ID) || !type.startsWith(schema.XSD_URI) || prop==null) return;
    if (isValidDatatype(type)) prop.addProperty(RDF.type,OWL.DatatypeProperty);
    else if (!schema.anyType.equals(type)) prop.addProperty(RDF.type,OWL.ObjectProperty);
  }

  /* return a resource representing the type */
  public static Resource toOWL(OntModel ont, String type) {
    if (type==null) return null;
    if (type.equals(schema.anySimpleType)) return RDFS.Literal;
    else if (type.equals(schema.ENTITY)) return ont.getResource(RDF.getURI()+"XMLLiteral");
    else if ( // structured type
      type.equals(schema.XSD_URI+"#anyType") ||
      type.equals(schema.XSD_URI+"#duration")) {
      return null;
    }
    // list type
    else if (type.equals(schema.XSD_URI+"#IDREFS"))
      return RDF.List;
    else if (type.equals(schema.XSD_URI+"#ENTITIES"))
      return toList(ont,type,schema.XSD_URI+"#ENTITY");
    else if (type.equals(schema.XSD_URI+"#NMTOKENS"))
      return toList(ont,type,schema.XSD_URI+"#NMTOKEN");
     
    else if ( // object reference
      type.equals(schema.XSD_URI+"#IDREF") ||
      type.equals(schema.XSD_URI+"#QName") ||
      type.equals(schema.XSD_URI+"#NOTATION")) {
      return null;
    }   
    else return ont.getResource(type);
  }
 
  public static boolean isID(Resource type) {
    if (!type.isAnon()) return type.getURI().equals(schema.ID);
    for (StmtIterator i = type.listProperties(RDFS.subClassOf); i.hasNext();) {
      Resource r = i.nextStatement().getResource();
      if (!type.equals(r) && isID(r)) return true;
    }
    return false
  }
 
  public static Resource toList(OntModel ont, String type, String itemType) {
    OntClass c = ont.createClass(type);
    Resource i = ont.getResource(itemType);
    c.addSuperClass(RDF.List);     
    c.addSuperClass(ont.createAllValuesFromRestriction(null,RDF.first,i));
    c.addSuperClass(ont.createAllValuesFromRestriction(null,RDF.rest,c));
    return c;   
  }
 
  public static void removeSubClass(OntModel ont, Resource c, Resource d) {
    ont.remove(ont.createStatement(c,RDFS.subClassOf,d));
  }

  public complexType[] getComplexType() {
    return complexType;
  }

  public element[] getElement() {
    return element;
  }

  public simpleType[] getSimpleType() {
    return simpleType;
  }

  public void setComplexType(complexType[] types) {
    complexType = types;
  }

  public void setElement(element[] elements) {
    element = elements;
  }

  public void setSimpleType(simpleType[] types) {
    simpleType = types;
  }

  public String getElementFormDefault() {
    return elementFormDefault;
  }

  public String getTargetNamespace() {
    return targetNamespace;
  }

  public void setElementFormDefault(String string) {
    elementFormDefault = string;
  }

  public void setTargetNamespace(String string) {
    //namespace =
    targetNamespace = string;
  }

  public attribute[] getAttribute() {
    return attribute;
  }

  public void setAttribute(attribute[] attributes) {
    attribute = attributes;
  }

  public String getAttributeFormDefault() {
    return attributeFormDefault;
  }

  public void setAttributeFormDefault(String string) {
    attributeFormDefault = string;
  }

  public String getBlockDefault() {
    return blockDefault;
  }

  public String getFinalDefault() {
    return finalDefault;
  }

  public void setBlockDefault(String string) {
    blockDefault = string;
  }

  public void setFinalDefault(String string) {
    finalDefault = string;
  }

  public Import[] get_import() {
    return _import;
  }

  public void set_import(Import[] imports) {
    _import = imports;
  }

  public attributeGroup[] getAttributeGroup() {
    return attributeGroup;
  }

  public void setAttributeGroup(attributeGroup[] groups) {
    attributeGroup = groups;
  }

  public Include[] getInclude() {
    return include;
  }

  public void setInclude(Include[] include) {
    this.include = include;
  }
 
  public void set_owner(XMLBean bean) {
    _owner = bean;
  }

  public group[] getGroup() {
    return group;
  }

  public void setGroup(group[] group) {
    this.group = group;
  }

  public String getVersion() {
    return version;
  }

  public void setVersion(String version) {
    this.version = version;
  }

  public URL get_url() {
    return _url;
  }

  public void set_url(URL _url) {
    this._url = _url;
  }

  public redefine[] getRedefine() {
    return redefine;
  }

  public void setRedefine(redefine[] redefine) {
    this.redefine = redefine;
  }

  public annotation[] getAnnotation() {
    return annotation;
  }

  public void setAnnotation(annotation[] annotation) {
    this.annotation = annotation;
  }

}
TOP

Related Classes of com.hp.gloze.www_w3_org_2001_XMLSchema.schema

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.