mirror of
https://github.com/AdaCore/xmlada.git
synced 2026-02-12 12:30:28 -08:00
4075 lines
141 KiB
Ada
4075 lines
141 KiB
Ada
------------------------------------------------------------------------------
|
|
-- XML/Ada - An XML suite for Ada95 --
|
|
-- --
|
|
-- Copyright (C) 2004-2017, AdaCore --
|
|
-- --
|
|
-- This library is free software; you can redistribute it and/or modify it --
|
|
-- under terms of the GNU General Public License as published by the Free --
|
|
-- Software Foundation; either version 3, or (at your option) any later --
|
|
-- version. This library is distributed in the hope that it will be useful, --
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
|
|
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
|
|
-- --
|
|
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
|
-- additional permissions described in the GCC Runtime Library Exception, --
|
|
-- version 3.1, as published by the Free Software Foundation. --
|
|
-- --
|
|
-- You should have received a copy of the GNU General Public License and --
|
|
-- a copy of the GCC Runtime Library Exception along with this program; --
|
|
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
|
-- <http://www.gnu.org/licenses/>. --
|
|
-- --
|
|
------------------------------------------------------------------------------
|
|
|
|
pragma Ada_05;
|
|
|
|
with Ada.Exceptions; use Ada.Exceptions;
|
|
with GNAT.Task_Lock; use GNAT.Task_Lock;
|
|
with Unicode; use Unicode;
|
|
with Unicode.CES; use Unicode.CES;
|
|
with Sax.Encodings; use Sax.Encodings;
|
|
with Sax.Exceptions; use Sax.Exceptions;
|
|
with Sax.Locators; use Sax.Locators;
|
|
with Sax.Symbols; use Sax.Symbols;
|
|
with Sax.Utils; use Sax.Utils;
|
|
with Schema.Simple_Types; use Schema.Simple_Types;
|
|
with Schema.Readers; use Schema.Readers;
|
|
with Ada.Unchecked_Deallocation;
|
|
with Ada.IO_Exceptions;
|
|
with Input_Sources.File; use Input_Sources.File;
|
|
|
|
package body Schema.Schema_Readers is
|
|
use Schema_State_Machines;
|
|
use Type_Tables, Element_HTables, Group_HTables;
|
|
use AttrGroup_HTables, Reference_HTables, Attribute_HTables;
|
|
|
|
Default_Contexts : constant := 30;
|
|
-- Default number of nested levels in a schema.
|
|
-- If the actual schema uses more, we will simply reallocate some memory.
|
|
|
|
Max_Max_Occurs : constant := 9_999;
|
|
-- Maximum value for maxOccurs.
|
|
-- Higher values result in an explosion in the number of states in the NFA,
|
|
-- so should not be used for now.
|
|
|
|
Max_Occurs_Warn : constant := 300;
|
|
-- Warn when maxOccurs is greater than this value, since this might
|
|
-- potentially result in a very large state machine. This is not a fatal
|
|
-- error though.
|
|
|
|
procedure Push_Context
|
|
(Handler : access Schema_Reader'Class; Ctx : Context);
|
|
-- Add a new context to the list
|
|
|
|
procedure Unchecked_Free is new Ada.Unchecked_Deallocation
|
|
(Attr_Array, Attr_Array_Access);
|
|
procedure Unchecked_Free is new Ada.Unchecked_Deallocation
|
|
(Context_Array, Context_Array_Access);
|
|
|
|
procedure Free (Shared : in out XSD_Data_Access);
|
|
-- Free [Shared] and its htables
|
|
|
|
procedure Free (Self : in out Type_Details_Access);
|
|
-- Free [Self], [Self.Next] and so on
|
|
|
|
procedure Create_NFA (Parser : access Schema_Reader);
|
|
-- Create the state machine from the registered elements and types
|
|
-- Return the start state for the current grammar (we do not use the
|
|
-- NFA's default start state, since each grammar has its own list of valid
|
|
-- toplevel elements.
|
|
|
|
function To_String (Final : Final_Status) return String;
|
|
|
|
function In_Redefine_Context
|
|
(Handler : Schema_Reader'Class) return Boolean;
|
|
-- Whether we are currently processing a <redefine> tag
|
|
|
|
function Resolve_QName
|
|
(Handler : access Schema_Reader'Class;
|
|
QName : Sax.Symbols.Symbol;
|
|
NS_If_Empty : Sax.Symbols.Symbol := Empty_String;
|
|
Loc : Location) return Qualified_Name;
|
|
-- Resolve namespaces for QName.
|
|
-- [NS_If_Empty] is used if no namespace was found for the element. This
|
|
-- will often be the target namespace of the schema.
|
|
|
|
procedure Internal_Parse
|
|
(Parser : in out Schema_Reader;
|
|
Input : in out Input_Sources.Input_Source'Class;
|
|
Default_Namespace : Symbol;
|
|
Do_Create_NFA : Boolean;
|
|
Do_Initialize_Shared : Boolean);
|
|
-- Internal version of [Parse], which allows reuse of the shared data.
|
|
-- This is useful while parsing a <include> XSD
|
|
|
|
procedure Insert_In_Type
|
|
(Handler : access Schema_Reader'Class;
|
|
Element : in out Type_Details_Access);
|
|
-- Insert Element in the type definition in [Handler.Contexts].
|
|
-- If there is an error inserting the element, an exception is raised and
|
|
-- [Element] is freed.
|
|
|
|
procedure Prepare_Type
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List;
|
|
Is_Simple : Boolean);
|
|
-- Prepare a type context (simpleType or complexType)
|
|
|
|
procedure Add_Type_Member
|
|
(Handler : access Schema_Reader'Class;
|
|
List : in out Type_Member_Array;
|
|
Member : Type_Member;
|
|
Loc : Location);
|
|
-- Add a new item in [List], and raise an exception if [List] is full.
|
|
|
|
procedure Compute_Blocks
|
|
(Atts : Sax_Attribute_List;
|
|
Handler : access Schema_Reader'Class;
|
|
Blocks : out Block_Status;
|
|
Is_Set : out Boolean;
|
|
Index : Integer);
|
|
-- Compute the list of blocked elements from the attribute "block".
|
|
|
|
function Compute_Final
|
|
(Atts : Sax_Attribute_List;
|
|
Handler : access Schema_Reader'Class;
|
|
Index : Integer) return Final_Status;
|
|
-- Compute the list of final attributes from value. Value is a list similar
|
|
-- to what is used for the "final" attribute of elements in a schema
|
|
|
|
function Compute_Form
|
|
(Atts : Sax_Attribute_List;
|
|
Handler : access Schema_Reader'Class;
|
|
Index : Integer) return Form_Type;
|
|
-- Parse the given attribute
|
|
|
|
procedure Append (List : in out Attr_Array_Access; Attr : Attr_Descr);
|
|
-- Add an attribute to the list
|
|
|
|
procedure Insert_Attribute
|
|
(Handler : access Schema_Reader'Class;
|
|
In_Context : Natural;
|
|
Attribute : Attr_Descr);
|
|
-- Insert attribute at the right location in In_Context.
|
|
|
|
function Process_Contents_From_Atts
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List;
|
|
Index : Integer) return Process_Contents_Type;
|
|
-- Get the value of processContents from the attributes
|
|
|
|
procedure Create_Element
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Notation
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Complex_Type
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Simple_Type
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Restriction
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_All
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Sequence
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Attribute
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Schema
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Extension
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_List
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Union
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Choice
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Redefine
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Include
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Group
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Attribute_Group
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Any
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Import
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
procedure Create_Any_Attribute
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List);
|
|
-- Create a new context for a specific tag:
|
|
-- resp. <element>, <complexType>, <restriction>, <all>, <sequence>,
|
|
-- <attribute>, <schema>, <extension>, <list>, <union>, <choice>,
|
|
-- <redefine>, <group>, <attributeGroup>, <any>, <import>, <anyAttribute>
|
|
|
|
procedure Finish_Element (Handler : access Schema_Reader'Class);
|
|
procedure Finish_Complex_Type (Handler : access Schema_Reader'Class);
|
|
procedure Finish_Simple_Type (Handler : access Schema_Reader'Class);
|
|
procedure Finish_Restriction (Handler : access Schema_Reader'Class);
|
|
procedure Finish_Extension (Handler : access Schema_Reader'Class);
|
|
procedure Finish_Attribute (Handler : access Schema_Reader'Class);
|
|
procedure Finish_Union (Handler : access Schema_Reader'Class);
|
|
procedure Finish_List (Handler : access Schema_Reader'Class);
|
|
procedure Finish_Group (Handler : access Schema_Reader'Class);
|
|
procedure Finish_Attribute_Group (Handler : access Schema_Reader'Class);
|
|
-- Finish the handling of various tags:
|
|
-- resp. <element>, <complexType>, <restriction>, <all>, <sequence>,
|
|
-- <extension>, <union>, <list>, <choice>, <group>
|
|
|
|
procedure Get_Occurs
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List;
|
|
Min_Occurs, Max_Occurs : out Occurrences);
|
|
-- Get the "minOccurs" and "maxOccurs" attributes
|
|
|
|
---------------
|
|
-- To_String --
|
|
---------------
|
|
|
|
function To_String (Final : Final_Status) return String is
|
|
begin
|
|
return "restr=" & Final (Final_Restriction)'Img
|
|
& " ext=" & Final (Final_Extension)'Img
|
|
& " union=" & Final (Final_Union)'Img
|
|
& " list=" & Final (Final_List)'Img;
|
|
end To_String;
|
|
|
|
-------------------------
|
|
-- In_Redefine_Context --
|
|
-------------------------
|
|
|
|
function In_Redefine_Context
|
|
(Handler : Schema_Reader'Class) return Boolean is
|
|
begin
|
|
for J in 1 .. Handler.Contexts_Last loop
|
|
if Handler.Contexts (J).Typ = Context_Redefine then
|
|
return True;
|
|
end if;
|
|
end loop;
|
|
return False;
|
|
end In_Redefine_Context;
|
|
|
|
----------------
|
|
-- Create_NFA --
|
|
----------------
|
|
|
|
procedure Create_NFA (Parser : access Schema_Reader) is
|
|
NFA : constant Schema_NFA_Access := Get_NFA (Get_Grammar (Parser.all));
|
|
Ref : constant Reference_HTable :=
|
|
Get_References (Get_Grammar (Parser.all));
|
|
|
|
Any_Simple_Type_Index : constant Type_Index :=
|
|
Get (Ref.all,
|
|
((Local => Parser.Any_Simple_Type,
|
|
NS => Parser.XML_Schema_URI), Ref_Type)).Typ;
|
|
|
|
Shared : XSD_Data_Access renames Parser.Shared;
|
|
|
|
package Type_HTables is new GNAT.Dynamic_HTables.Simple_HTable
|
|
(Header_Num => Header_Num,
|
|
Element => Internal_Type_Index,
|
|
No_Element => No_Internal_Type_Index,
|
|
Key => Qualified_Name,
|
|
Hash => Hash,
|
|
Equal => "=");
|
|
use Type_HTables;
|
|
Types : Type_HTables.Instance;
|
|
|
|
procedure Process_Global_Element
|
|
(Info : in out Element_Descr; Start_At : State);
|
|
procedure Process_Type (Info : in out Internal_Type_Descr);
|
|
procedure Process_Details
|
|
(In_Type : access Type_Descr;
|
|
Details : Type_Details_Access;
|
|
Start, From : State;
|
|
Nested_End : out State;
|
|
Mask : out Visited_All_Children);
|
|
-- [Start] is the start of the current nested.
|
|
-- [Mask] is the mask to apply to a closing transition out of a <all>
|
|
-- node. It is only set if Details.Kind = Type_All.
|
|
|
|
procedure Create_Element_State
|
|
(Info : in out Element_Descr;
|
|
Start, From : State;
|
|
Global : Boolean;
|
|
S1, S2 : out State;
|
|
Trans_Kind : Transition_Kind;
|
|
All_Child_Index : Integer := 0);
|
|
-- Create (and decorate) the nodes [S1]..[S2] corresponding to an
|
|
-- <element>. A link is created [From]->[S1].
|
|
-- [Start] is the first element of the current nested machine.
|
|
-- Trans_Kind is the kind of the first transition, from From to the
|
|
-- first created state. This transition is associated with the name of
|
|
-- the element.
|
|
-- All_Child_Index indicates the index of the created transition in all
|
|
-- the children of an <all> node. This is used to memory efficiently
|
|
-- which transitions have already been visited for this <all>.
|
|
|
|
type Type_Descr_Access is access all Type_Descr;
|
|
procedure Create_Simple_Type
|
|
(J : Internal_Type_Index;
|
|
Descr : out Type_Descr_Access;
|
|
Index : out Type_Index);
|
|
-- Create the new simple type info at index [J]
|
|
|
|
procedure Get_Type_Descr
|
|
(Name : Qualified_Name;
|
|
Loc : Location;
|
|
NFA_Type : out Type_Index;
|
|
Internal_Type : out Internal_Type_Index);
|
|
-- Lookup the type information in the grammar. This type information
|
|
-- could be in several places:
|
|
-- - Either defined in the current XSD and its <input>: in that case,
|
|
-- [Internal_Type] will be set.
|
|
-- - Or in a previously loaded XSD. In that case, it is set to
|
|
-- [No_Internal_Type_Index]
|
|
|
|
procedure Lookup_Simple_Type
|
|
(Name : Qualified_Name;
|
|
Loc : Location;
|
|
Descr : out Type_Descr_Access;
|
|
Index : out Type_Index);
|
|
-- Search for the simpleType [Name]
|
|
|
|
procedure Add_Attributes
|
|
(List : in out Attributes_List;
|
|
Attrs : Attr_Array_Access;
|
|
Processed_Groups : in out AttrGroup_HTables.Instance;
|
|
As_Restriction : Boolean;
|
|
Had_Any : in out Boolean);
|
|
-- Create List from the list of attributes or attribute groups in
|
|
-- [Attrs]. [Had_Any] is set to true if a <anyAttribute> was
|
|
-- encountered. The caller should first set it to False.
|
|
|
|
procedure Check_Unique_Particle_Attribution
|
|
(Details : Type_Details_Access);
|
|
-- Check that all elements in the content model are unique (we must not
|
|
-- have two elements that compete with each other).
|
|
|
|
procedure Create_Global_Attributes (Attr : Internal_Attribute_Descr);
|
|
-- Register a global attribute.
|
|
|
|
procedure Resolve_Attribute_Type
|
|
(Attr : in out Internal_Attribute_Descr;
|
|
Loc : Sax.Locators.Location);
|
|
-- Set [Attr.Descr.Simple_Type] to the appropriate value, after looking
|
|
-- up the type
|
|
|
|
--------------------------
|
|
-- Create_Element_State --
|
|
--------------------------
|
|
|
|
procedure Create_Element_State
|
|
(Info : in out Element_Descr;
|
|
Start, From : State;
|
|
Global : Boolean;
|
|
S1, S2 : out State;
|
|
Trans_Kind : Transition_Kind;
|
|
All_Child_Index : Integer := 0)
|
|
is
|
|
pragma Unreferenced (Start);
|
|
Real : Element_Descr;
|
|
Trans : Transition_Descr;
|
|
TRef : Global_Reference := No_Global_Reference;
|
|
S : State := No_State;
|
|
|
|
function Build_Trans
|
|
(N : Qualified_Name; F : Form_Type) return Transition_Descr;
|
|
function Build_Trans
|
|
(N : Qualified_Name; F : Form_Type) return Transition_Descr is
|
|
begin
|
|
case Trans_Kind is
|
|
when Transition_Symbol =>
|
|
return (Transition_Symbol, N, F, All_Child_Index => 0);
|
|
when Transition_Symbol_From_All =>
|
|
return (Transition_Symbol_From_All, N, F,
|
|
All_Child_Index => All_Child_Index);
|
|
when others =>
|
|
raise Program_Error with "Invalid transition type";
|
|
end case;
|
|
end Build_Trans;
|
|
|
|
begin
|
|
if Info.Is_Abstract then
|
|
-- ??? Should use the substitutionGroup elements, instead
|
|
S1 := No_State;
|
|
S2 := No_State;
|
|
|
|
Validation_Error
|
|
(Parser,
|
|
"Abstract elements not handled yet",
|
|
Except => XML_Not_Implemented'Identity);
|
|
return;
|
|
end if;
|
|
|
|
S1 := NFA.Add_State;
|
|
Info.S := S1;
|
|
|
|
if Debug then
|
|
Debug_Output ("Create_Element_State S1 for element "
|
|
& To_QName (Info.Name) & To_QName (Info.Ref)
|
|
& S1'Img);
|
|
end if;
|
|
|
|
-- Resolve element references
|
|
|
|
if Info.Name = No_Qualified_Name then
|
|
Real := Get (Shared.Global_Elements, Info.Ref);
|
|
if Real = No_Element_Descr then
|
|
TRef := Get (Ref.all, (Info.Ref, Ref_Element));
|
|
if TRef = No_Global_Reference then
|
|
Validation_Error
|
|
(Parser, "Unknown refed element " & To_QName (Info.Ref),
|
|
Info.Loc);
|
|
end if;
|
|
|
|
S := TRef.Element;
|
|
Trans := Build_Trans (Info.Ref, Info.Form);
|
|
|
|
else
|
|
Trans := Build_Trans (Real.Name, Info.Form);
|
|
S := Real.S;
|
|
end if;
|
|
|
|
if S /= No_State then
|
|
if Debug then
|
|
Debug_Output ("copying data from" & S'Img & " to" & S1'Img);
|
|
end if;
|
|
NFA.Get_Data (S1).all := NFA.Get_Data (S).all;
|
|
NFA.Set_Nested (S1, NFA.Get_Nested (S));
|
|
end if;
|
|
|
|
else
|
|
declare
|
|
NFA_Type : Type_Index;
|
|
Internal_Type : Internal_Type_Index;
|
|
Data : access State_Data;
|
|
begin
|
|
Real := Info;
|
|
Trans := Build_Trans (Real.Name, Info.Form);
|
|
|
|
-- Create nested NFA for the type, if needed
|
|
|
|
if Real.Typ /= No_Qualified_Name then
|
|
Get_Type_Descr (Real.Typ, Info.Loc, NFA_Type, Internal_Type);
|
|
|
|
elsif Real.Local_Type /= No_Internal_Type_Index then
|
|
Internal_Type := Real.Local_Type;
|
|
NFA_Type := Shared.Types.Table (Internal_Type).In_NFA;
|
|
else
|
|
-- "<anyType>" (3.3.2.1 {type definition})
|
|
NFA_Type := No_Type_Index;
|
|
end if;
|
|
|
|
if Info.Substitution_Group /= No_Qualified_Name then
|
|
-- ??? Handling of substitutionGroup: the type of the
|
|
-- element is the same as the head unless overridden.
|
|
Validation_Error
|
|
(Parser,
|
|
"substitutionGroup not supported",
|
|
Except => XML_Not_Implemented'Identity);
|
|
end if;
|
|
|
|
Data := NFA.Get_Data (S1);
|
|
|
|
if NFA_Type /= No_Type_Index then
|
|
Data.all := State_Data'(Simple => NFA_Type,
|
|
Fixed => No_Symbol, -- See below
|
|
Default => Info.Default,
|
|
Nillable => Info.Nillable,
|
|
Block => Info.Block);
|
|
NFA.Set_Nested
|
|
(S1, NFA.Create_Nested
|
|
(Get_Type_Descr (NFA, NFA_Type).Complex_Content));
|
|
else
|
|
NFA.Set_Nested (S1, NFA.Ur_Type (Process_Lax));
|
|
Data.Default := Info.Default;
|
|
Data.Block := Info.Block;
|
|
Data.Nillable := Info.Nillable;
|
|
end if;
|
|
|
|
-- Check that the fixed value is valid
|
|
|
|
if Info.Fixed /= No_Symbol
|
|
and then NFA.Get_Data (S1).Simple /= No_Type_Index
|
|
then
|
|
Normalize_And_Validate
|
|
(Parser => Parser,
|
|
Simple => Get_Type_Descr
|
|
(NFA, NFA.Get_Data (S1).Simple).Simple_Content,
|
|
Fixed => Info.Fixed,
|
|
Loc => Info.Loc);
|
|
end if;
|
|
|
|
Data.Fixed := Info.Fixed;
|
|
end;
|
|
end if;
|
|
|
|
-- Link with previous element
|
|
|
|
NFA.Add_Transition (From, S1, Trans);
|
|
|
|
S2 := NFA.Add_State;
|
|
if Debug then
|
|
Debug_Output ("Create_Element_State S2 for element "
|
|
& To_QName (Info.Name) & To_QName (Info.Ref)
|
|
& S2'Img);
|
|
end if;
|
|
|
|
if NFA.Get_Nested (S1) /= No_Nested then
|
|
NFA.On_Empty_Nested_Exit (S1, S2); -- a complexType
|
|
else
|
|
NFA.Add_Transition (S1, S2, (Kind => Transition_Close));
|
|
end if;
|
|
|
|
-- Save this element for later reuse in other namespaces
|
|
|
|
if Global then
|
|
if Debug then
|
|
Debug_Output ("Global elem: " & To_QName (Real.Name));
|
|
end if;
|
|
Set (Ref.all,
|
|
(Kind => Ref_Element, Name => Real.Name, Element => S1));
|
|
end if;
|
|
end Create_Element_State;
|
|
|
|
----------------------------
|
|
-- Process_Global_Element --
|
|
----------------------------
|
|
|
|
procedure Process_Global_Element
|
|
(Info : in out Element_Descr; Start_At : State)
|
|
is
|
|
S1, S2 : State;
|
|
begin
|
|
Create_Element_State
|
|
(Info, Start_At, Start_At, True, S1, S2, Transition_Symbol);
|
|
|
|
if S2 /= No_State then
|
|
NFA.Add_Empty_Transition (S2, Final_State);
|
|
end if;
|
|
end Process_Global_Element;
|
|
|
|
--------------------
|
|
-- Get_Type_Descr --
|
|
--------------------
|
|
|
|
procedure Get_Type_Descr
|
|
(Name : Qualified_Name;
|
|
Loc : Location;
|
|
NFA_Type : out Type_Index;
|
|
Internal_Type : out Internal_Type_Index)
|
|
is
|
|
TRef : Global_Reference;
|
|
begin
|
|
Internal_Type := Get (Types, Name);
|
|
if Internal_Type = No_Internal_Type_Index then
|
|
TRef := Get (Ref.all, (Name, Ref_Type));
|
|
if TRef = No_Global_Reference then
|
|
Validation_Error
|
|
(Parser, "Unknown type " & To_QName (Name), Loc);
|
|
end if;
|
|
|
|
NFA_Type := TRef.Typ;
|
|
else
|
|
NFA_Type := Shared.Types.Table (Internal_Type).In_NFA;
|
|
end if;
|
|
|
|
if Name = (NS => Parser.XML_Schema_URI, Local => Parser.IDREF)
|
|
or else
|
|
Name = (NS => Parser.XML_Schema_URI, Local => Parser.IDREFS)
|
|
then
|
|
Validation_Error
|
|
(Parser,
|
|
"Unsupported type IDREF and IDREFS",
|
|
Loc => Loc,
|
|
Except => XML_Not_Implemented'Identity);
|
|
end if;
|
|
end Get_Type_Descr;
|
|
|
|
------------------------
|
|
-- Lookup_Simple_Type --
|
|
------------------------
|
|
|
|
procedure Lookup_Simple_Type
|
|
(Name : Qualified_Name;
|
|
Loc : Location;
|
|
Descr : out Type_Descr_Access;
|
|
Index : out Type_Index)
|
|
is
|
|
TRef : Global_Reference;
|
|
Internal : Internal_Type_Index;
|
|
begin
|
|
TRef := Get (Ref.all, (Name, Ref_Type));
|
|
if TRef = No_Global_Reference then
|
|
Validation_Error
|
|
(Parser, "Unknown type " & To_QName (Name), Loc);
|
|
end if;
|
|
|
|
Index := TRef.Typ;
|
|
Descr := Type_Descr_Access (Get_Type_Descr (NFA, Index));
|
|
|
|
if Descr.Simple_Content = No_Simple_Type_Index then
|
|
if Debug then
|
|
Debug_Output ("Lookup_Simple_Type: generate "
|
|
& To_QName (Name) & " early");
|
|
end if;
|
|
|
|
Internal := Get (Types, Name);
|
|
if Internal = No_Internal_Type_Index then
|
|
Validation_Error
|
|
(Parser,
|
|
"Type is not a simple type: " & To_QName (Name), Loc);
|
|
end if;
|
|
|
|
Create_Simple_Type (Internal, Descr, Index);
|
|
end if;
|
|
end Lookup_Simple_Type;
|
|
|
|
---------------------------------------
|
|
-- Check_Unique_Particle_Attribution --
|
|
---------------------------------------
|
|
|
|
procedure Check_Unique_Particle_Attribution
|
|
(Details : Type_Details_Access)
|
|
is
|
|
Duplicates : Element_HTables.Instance;
|
|
-- Used to check for duplicate elements within a sequence or choice.
|
|
-- ??? Could use a htable of locations, so that we can point to the
|
|
-- two duplicate declarations.
|
|
|
|
T : Type_Details_Access;
|
|
Elem : Element_Descr;
|
|
|
|
begin
|
|
case Details.Kind is
|
|
when Type_Sequence =>
|
|
T := Details.First_In_Seq;
|
|
when Type_Choice =>
|
|
T := Details.First_In_Choice;
|
|
when Type_All =>
|
|
T := Details.First_In_All;
|
|
when others =>
|
|
raise Program_Error with "Internal error";
|
|
end case;
|
|
|
|
while T /= null loop
|
|
case T.Kind is
|
|
when Type_Element =>
|
|
if T.Element.Name /= No_Qualified_Name then
|
|
Elem := Element_HTables.Get (Duplicates, T.Element.Name);
|
|
|
|
if Elem /= No_Element_Descr then
|
|
-- It is always invalid to have an element with the
|
|
-- same name but with different types in the same
|
|
-- model, even if there is no ambiguity (for instance
|
|
-- in a sequence).
|
|
|
|
if Elem.Typ /= No_Qualified_Name
|
|
and then Elem.Typ /= T.Element.Typ
|
|
then
|
|
Validation_Error
|
|
(Parser,
|
|
"Multiple elements with name '"
|
|
& To_QName (T.Element.Name)
|
|
& "', with different types, appear in the model"
|
|
& " group",
|
|
Details.Loc);
|
|
end if;
|
|
|
|
-- In a <choice> or <all>, we cannot have the same
|
|
-- element multiple times, since that would be
|
|
-- ambiguous.
|
|
|
|
if Details.Kind = Type_Choice
|
|
or else Details.Kind = Type_All
|
|
then
|
|
Validation_Error
|
|
(Parser,
|
|
"'" & To_QName (T.Element.Name) & "' and '"
|
|
& To_QName (Elem.Name) & "' violate the Unique"
|
|
& " Particle Attribution rule, creating an"
|
|
& " ambiguity for the validation",
|
|
Details.Loc);
|
|
end if;
|
|
|
|
else
|
|
Element_HTables.Set
|
|
(Duplicates, T.Element.Name, T.Element);
|
|
end if;
|
|
end if;
|
|
|
|
when Type_Group =>
|
|
null;
|
|
|
|
when others =>
|
|
-- ??? Should check, in particular for groups or nested
|
|
-- sequences (we can have a Sequence that contains choices)
|
|
null;
|
|
end case;
|
|
|
|
T := T.Next;
|
|
end loop;
|
|
|
|
Reset (Duplicates);
|
|
|
|
exception
|
|
when others =>
|
|
Reset (Duplicates);
|
|
raise;
|
|
end Check_Unique_Particle_Attribution;
|
|
|
|
---------------------
|
|
-- Process_Details --
|
|
---------------------
|
|
|
|
procedure Process_Details
|
|
(In_Type : access Type_Descr;
|
|
Details : Type_Details_Access;
|
|
Start, From : State;
|
|
Nested_End : out State;
|
|
Mask : out Visited_All_Children)
|
|
is
|
|
S, S1 : State;
|
|
T : Type_Details_Access;
|
|
Gr : Group_Descr;
|
|
|
|
begin
|
|
Nested_End := From;
|
|
Mask := 0;
|
|
|
|
if Details = null then
|
|
return;
|
|
end if;
|
|
|
|
Details.In_Process := True;
|
|
|
|
case Details.Kind is
|
|
when Type_Empty =>
|
|
null;
|
|
|
|
when Type_Sequence =>
|
|
Check_Unique_Particle_Attribution (Details);
|
|
|
|
S := From;
|
|
T := Details.First_In_Seq;
|
|
while T /= null loop
|
|
Process_Details (In_Type, T, Start, S, Nested_End, Mask);
|
|
S1 := Nested_End;
|
|
|
|
-- We can have one element start exactly where the other
|
|
-- finishes. Otherwise we have issues with the following
|
|
-- sequence:
|
|
-- <sequence>
|
|
-- <element name="a" minOccurs="0" maxOccurs="unbounded"/>
|
|
-- <element name="b" minOccurs="0" maxOccurs="unbounded"/>
|
|
-- </sequence>
|
|
-- which would allow any number of a, any number of b, and
|
|
-- again any number of a (because of empty transition from
|
|
-- end of "b*" that goes back to the beginning of "b*",
|
|
-- which would be the same as end of "a*", which has empty
|
|
-- transition to "a*". The following empty transition
|
|
-- ensures that end of "a*" is not same as beginning of
|
|
-- "b*".
|
|
S := NFA.Add_State;
|
|
NFA.Add_Empty_Transition (S1, S);
|
|
|
|
T := T.Next;
|
|
end loop;
|
|
Nested_End := S;
|
|
|
|
when Type_Choice =>
|
|
Check_Unique_Particle_Attribution (Details);
|
|
|
|
T := Details.First_In_Choice;
|
|
Nested_End := NFA.Add_State;
|
|
while T /= null loop
|
|
S1 := NFA.Add_State;
|
|
NFA.Add_Empty_Transition (From, S1);
|
|
|
|
Process_Details (In_Type, T, Start, S1, S, Mask);
|
|
NFA.Add_Empty_Transition (S, Nested_End);
|
|
|
|
T := T.Next;
|
|
end loop;
|
|
|
|
when Type_All =>
|
|
Check_Unique_Particle_Attribution (Details);
|
|
|
|
if Details.First_In_All /= null then
|
|
declare
|
|
Count : Natural := 0;
|
|
begin
|
|
Mask := 0;
|
|
T := Details.First_In_All;
|
|
while T /= null loop
|
|
pragma Assert
|
|
(T.Kind = Type_Element,
|
|
"Children of <all> must be simple elements");
|
|
|
|
-- If the element has maxOccurs=0, there is no need to
|
|
-- put it in the state machine.
|
|
|
|
if T.Max_Occurs.Value /= 0 then
|
|
Create_Element_State
|
|
(T.Element, Start, From, False,
|
|
S1 => S1,
|
|
S2 => S,
|
|
Trans_Kind => Transition_Symbol_From_All,
|
|
All_Child_Index => Count);
|
|
|
|
if T.Min_Occurs.Value = 1 then
|
|
-- The child is mandatory
|
|
Mask := Mask or (2 ** Count);
|
|
end if;
|
|
|
|
Count := Count + 1;
|
|
|
|
-- All elements, after being processed, come back
|
|
-- to <all> itself. The latter is in charge of
|
|
-- deciding, through the subprogram Match, which
|
|
-- transitions are valid in the current state.
|
|
NFA.Add_Empty_Transition (S, Start);
|
|
end if;
|
|
|
|
T := T.Next;
|
|
end loop;
|
|
|
|
-- The actual end of <all> is through a conditional empty
|
|
-- transition controlled by Match.
|
|
|
|
Nested_End := NFA.Add_State;
|
|
NFA.Add_Empty_Transition (From, Nested_End);
|
|
end;
|
|
end if;
|
|
|
|
when Type_Element =>
|
|
Create_Element_State
|
|
(Details.Element, Start, From, False, S1, Nested_End,
|
|
Transition_Symbol);
|
|
|
|
when Type_Group =>
|
|
Gr := Get (Parser.Shared.Global_Groups, Details.Group.Ref);
|
|
if Gr = No_Group_Descr then
|
|
Validation_Error
|
|
(Parser,
|
|
"No group """ & To_QName (Details.Group.Ref) & '"',
|
|
Details.Group.Loc);
|
|
|
|
elsif Gr.Details.In_Process then
|
|
Validation_Error
|
|
(Parser,
|
|
"Circular group reference for "
|
|
& To_QName (Details.Group.Ref),
|
|
Details.Group.Loc);
|
|
end if;
|
|
|
|
Process_Details
|
|
(In_Type, Gr.Details, Start, From, Nested_End, Mask);
|
|
|
|
when Type_Extension =>
|
|
declare
|
|
NFA_Type : Type_Index; -- Attributes of the base type
|
|
Internal_Type : Internal_Type_Index;
|
|
Base_Descr : access Type_Descr;
|
|
begin
|
|
Get_Type_Descr
|
|
(Name => Details.Extension.Base,
|
|
Loc => Details.Extension.Loc,
|
|
NFA_Type => NFA_Type,
|
|
Internal_Type => Internal_Type);
|
|
|
|
Base_Descr := Get_Type_Descr (NFA, NFA_Type);
|
|
|
|
if Base_Descr.Final (Final_Extension) then
|
|
Validation_Error
|
|
(Parser,
|
|
To_QName (Base_Descr.Name)
|
|
& " is final for extensions",
|
|
Details.Extension.Loc);
|
|
end if;
|
|
|
|
if Base_Descr.Simple_Content = No_Simple_Type_Index then
|
|
if Internal_Type /= No_Internal_Type_Index then
|
|
-- We have all the details, and just have to copy them
|
|
-- Details might be null, for instance for an
|
|
-- <extension> that just adds attributes
|
|
|
|
if Shared.Types.Table (Internal_Type).Details /= null
|
|
and then
|
|
Shared.Types.Table (Internal_Type)
|
|
.Details.In_Process
|
|
then
|
|
Validation_Error
|
|
(Parser,
|
|
"Circular inheritance of type "
|
|
& To_QName (Details.Extension.Base),
|
|
Details.Extension.Loc);
|
|
end if;
|
|
|
|
Process_Details
|
|
(In_Type,
|
|
Shared.Types.Table (Internal_Type).Details,
|
|
Start, From, S, Mask);
|
|
|
|
else
|
|
-- ??? Should copy the nested NFA for TyS
|
|
Validation_Error
|
|
(Parser,
|
|
"Extension's base in a different file "
|
|
& To_QName (Details.Extension.Base),
|
|
Details.Extension.Loc,
|
|
XML_Not_Implemented'Identity);
|
|
end if;
|
|
|
|
Process_Details
|
|
(In_Type,
|
|
Details.Extension.Details, Start, S, Nested_End,
|
|
Mask);
|
|
else
|
|
-- ??? Should handle simple types
|
|
Nested_End := Start;
|
|
|
|
-- The test is correct. However, it makes
|
|
-- msData/particles/particlesZ031.xsd fails, because the
|
|
-- test is incorrect. The test pretends that the XSD is
|
|
-- valid, but later checkins in the testsuite have proven
|
|
-- it incorrect. The following Ada test would make the
|
|
-- test pass, but then
|
|
-- MS-Additional2006-07-15/addB036
|
|
-- fails
|
|
--
|
|
-- and then
|
|
-- (Internal_Type = No_Internal_Type_Index
|
|
-- or else Shared.Types.Table (Internal_Type).Is_Simple)
|
|
|
|
if not Details.Simple_Content then
|
|
Validation_Error
|
|
(Parser,
|
|
"base type specified in complexContent definition"
|
|
& " must be a complex type",
|
|
Details.Extension.Loc);
|
|
end if;
|
|
end if;
|
|
|
|
In_Type.Extension_Of := NFA_Type;
|
|
In_Type.Restriction_Of := No_Type_Index;
|
|
end;
|
|
|
|
when Type_Restriction =>
|
|
declare
|
|
Internal : Internal_Type_Index;
|
|
NFA_Type : Type_Index; -- Attributes of the base type
|
|
Base_Descr : access Type_Descr;
|
|
begin
|
|
Get_Type_Descr
|
|
(Name => Details.Restriction.Base,
|
|
Loc => No_Location,
|
|
NFA_Type => NFA_Type,
|
|
Internal_Type => Internal);
|
|
|
|
Base_Descr := Get_Type_Descr (NFA, NFA_Type);
|
|
|
|
if Base_Descr.Final (Final_Restriction) then
|
|
Validation_Error
|
|
(Parser,
|
|
To_QName (Base_Descr.Name)
|
|
& " is final for restrictions",
|
|
Details.Restriction.Loc);
|
|
end if;
|
|
|
|
if Base_Descr.Simple_Content = No_Simple_Type_Index then
|
|
if Internal /= No_Internal_Type_Index
|
|
and then Shared.Types.Table (Internal).Details /= null
|
|
and then
|
|
Shared.Types.Table (Internal).Details.In_Process
|
|
then
|
|
Validation_Error
|
|
(Parser,
|
|
"Circular inheritance of type "
|
|
& To_QName (Details.Restriction.Base),
|
|
Details.Restriction.Loc);
|
|
end if;
|
|
|
|
Process_Details
|
|
(In_Type,
|
|
Details.Restriction.Details, Start, From, Nested_End,
|
|
Mask);
|
|
else
|
|
-- ??? Should handle simple types
|
|
Nested_End := Start;
|
|
|
|
if not Details.Simple_Content_Restriction then
|
|
Validation_Error
|
|
(Parser,
|
|
"base type specified in complexContent definition"
|
|
& " must be a complex type",
|
|
Details.Restriction.Loc);
|
|
end if;
|
|
end if;
|
|
|
|
In_Type.Restriction_Of := NFA_Type;
|
|
In_Type.Extension_Of := No_Type_Index;
|
|
end;
|
|
|
|
when Type_Any =>
|
|
S := NFA.Add_State; -- ((Simple => 1, others => <>));
|
|
NFA.Set_Nested (S, Ur_Type (NFA, Details.Any.Process_Contents));
|
|
|
|
NFA.Add_Transition
|
|
(From, S, (Transition_Any,
|
|
Combine (Parser.Grammar, No_Any_Descr,
|
|
Local_Process => Details.Any.Process_Contents,
|
|
Local => Details.Any.Namespaces,
|
|
As_Restriction => False,
|
|
Target_NS => Details.Any.Target_NS)));
|
|
|
|
Nested_End := NFA.Add_State;
|
|
NFA.On_Empty_Nested_Exit (S, Nested_End);
|
|
end case;
|
|
|
|
-- For <all> elements, we can only have maxOccurs=1 and minOccurs=0
|
|
-- or 1. In the case of minOccurs=0, and since we use conditional
|
|
-- links there, we cannot create a direct empty transition from the
|
|
-- start state to the final state (since the
|
|
-- transition_close_from_all is on exit of that final state, and
|
|
-- thus would be *after* the new empty transition). So this case
|
|
-- is handled specially in Process_Type.
|
|
|
|
if Details.Kind /= Type_All then
|
|
if Details.Max_Occurs.Unbounded then
|
|
Nested_End := NFA.Repeat
|
|
(From, Nested_End, Details.Min_Occurs.Value,
|
|
Natural'Last);
|
|
else
|
|
Nested_End := NFA.Repeat
|
|
(From, Nested_End, Details.Min_Occurs.Value,
|
|
Details.Max_Occurs.Value);
|
|
end if;
|
|
end if;
|
|
|
|
Details.In_Process := False;
|
|
end Process_Details;
|
|
|
|
----------------------------
|
|
-- Resolve_Attribute_Type --
|
|
----------------------------
|
|
|
|
procedure Resolve_Attribute_Type
|
|
(Attr : in out Internal_Attribute_Descr;
|
|
Loc : Sax.Locators.Location)
|
|
is
|
|
TRef : Global_Reference;
|
|
NFA_Type : Type_Index; -- In NFA
|
|
begin
|
|
if Attr.Local_Type /= No_Internal_Type_Index then
|
|
NFA_Type := Shared.Types.Table (Attr.Local_Type).In_NFA;
|
|
Attr.Descr.Simple_Type :=
|
|
Get_Type_Descr (NFA, NFA_Type).Simple_Content;
|
|
|
|
elsif Attr.Typ = No_Qualified_Name then
|
|
-- ??? Type should be ur-type (3.2.2)
|
|
null;
|
|
|
|
else
|
|
TRef := Get (Ref.all, (Attr.Typ, Ref_Type));
|
|
if TRef = No_Global_Reference then
|
|
Validation_Error
|
|
(Parser,
|
|
"Unknown type: " & To_QName (Attr.Typ),
|
|
Loc);
|
|
|
|
else
|
|
Attr.Descr.Simple_Type :=
|
|
Get_Type_Descr (NFA, TRef.Typ).Simple_Content;
|
|
end if;
|
|
end if;
|
|
end Resolve_Attribute_Type;
|
|
|
|
--------------------
|
|
-- Add_Attributes --
|
|
--------------------
|
|
|
|
procedure Add_Attributes
|
|
(List : in out Attributes_List;
|
|
Attrs : Attr_Array_Access;
|
|
Processed_Groups : in out AttrGroup_HTables.Instance;
|
|
As_Restriction : Boolean;
|
|
Had_Any : in out Boolean)
|
|
is
|
|
Gr : AttrGroup_Descr;
|
|
TRef : Global_Reference;
|
|
begin
|
|
if Attrs /= null then
|
|
for A in Attrs'Range loop
|
|
case Attrs (A).Kind is
|
|
when Kind_Unset =>
|
|
null;
|
|
when Kind_Group =>
|
|
Gr := Get (Shared.Global_AttrGroups, Attrs (A).Group_Ref);
|
|
if Gr = No_AttrGroup_Descr then
|
|
Validation_Error
|
|
(Parser,
|
|
"Reference to undefined attributeGroup: "
|
|
& To_QName (Attrs (A).Group_Ref),
|
|
Attrs (A).Loc);
|
|
|
|
elsif Get (Processed_Groups, Gr.Name) /=
|
|
No_AttrGroup_Descr
|
|
then
|
|
Validation_Error
|
|
(Parser,
|
|
"attributeGroup """ & To_QName (Attrs (A).Group_Ref)
|
|
& """ has circular reference",
|
|
Attrs (A).Loc);
|
|
else
|
|
Set (Processed_Groups, Gr.Name, Gr);
|
|
Add_Attributes
|
|
(List, Gr.Attributes, Processed_Groups,
|
|
As_Restriction, Had_Any);
|
|
end if;
|
|
|
|
when Kind_Attribute =>
|
|
if Attrs (A).Attr.Ref /= No_Qualified_Name then
|
|
TRef := Get
|
|
(Ref.all, (Attrs (A).Attr.Ref, Ref_Attribute));
|
|
|
|
if TRef = No_Global_Reference then
|
|
Validation_Error
|
|
(Parser,
|
|
"Unknown referenced attribute: "
|
|
& To_QName (Attrs (A).Attr.Ref),
|
|
Attrs (A).Loc);
|
|
end if;
|
|
|
|
Add_Attribute
|
|
(Parser, List,
|
|
Attribute => Attrs (A).Attr.Descr,
|
|
Ref => TRef.Attributes.Named,
|
|
Loc => Attrs (A).Loc);
|
|
|
|
else
|
|
Resolve_Attribute_Type (Attrs (A).Attr, Attrs (A).Loc);
|
|
|
|
if Attrs (A).Attr.Any /= No_Internal_Any_Descr then
|
|
Had_Any := True;
|
|
Add_Any_Attribute
|
|
(Parser.Grammar, List, Attrs (A).Attr.Any,
|
|
As_Restriction);
|
|
|
|
else
|
|
Add_Attribute
|
|
(Parser, List, Attrs (A).Attr.Descr,
|
|
Loc => Attrs (A).Loc);
|
|
end if;
|
|
end if;
|
|
end case;
|
|
end loop;
|
|
end if;
|
|
end Add_Attributes;
|
|
|
|
------------------------
|
|
-- Create_Simple_Type --
|
|
------------------------
|
|
|
|
procedure Create_Simple_Type
|
|
(J : Internal_Type_Index;
|
|
Descr : out Type_Descr_Access;
|
|
Index : out Type_Index)
|
|
is
|
|
Info : Internal_Type_Descr renames Shared.Types.Table (J);
|
|
Simple : Simple_Type_Descr;
|
|
Index_In_Simple : Natural;
|
|
Internal : Internal_Simple_Type_Descr;
|
|
Result : Simple_Type_Index;
|
|
begin
|
|
Index := Info.In_NFA;
|
|
Descr := Type_Descr_Access (NFA.Get_Type_Descr (Index));
|
|
|
|
Result := Descr.Simple_Content;
|
|
if Result /= No_Simple_Type_Index then
|
|
if Debug then
|
|
Debug_Output ("Create_Simple_Type: already done "
|
|
& To_QName (Info.Properties.Name));
|
|
end if;
|
|
return;
|
|
end if;
|
|
|
|
Internal := Info.Simple;
|
|
if Internal.Kind = Simple_Type_None then
|
|
-- Not a simple type, nothing to do
|
|
Descr := null;
|
|
return;
|
|
end if;
|
|
|
|
if Internal.In_Process then
|
|
Validation_Error
|
|
(Parser,
|
|
"Circular inheritance of type "
|
|
& To_QName (Info.Properties.Name),
|
|
Info.Loc);
|
|
end if;
|
|
|
|
if Debug then
|
|
Debug_Output
|
|
("Create_Simple_Type " & To_QName (Info.Properties.Name)
|
|
& " " & Internal.Kind'Img);
|
|
end if;
|
|
|
|
Info.Simple.In_Process := True;
|
|
|
|
case Internal.Kind is
|
|
when Simple_Type_None =>
|
|
Descr := null;
|
|
return;
|
|
|
|
when Simple_Type =>
|
|
-- ??? Shouldn't we set Simple_Content as well ?
|
|
|
|
Descr.Restriction_Of := Any_Simple_Type_Index;
|
|
|
|
when Simple_Type_Union =>
|
|
Simple := (Kind => Primitive_Union,
|
|
Union => (others => No_Simple_Type_Index),
|
|
others => <>);
|
|
Index_In_Simple := Simple.Union'First;
|
|
|
|
for U in Internal.Union_Items'Range loop
|
|
declare
|
|
Member : constant Type_Member := Internal.Union_Items (U);
|
|
Item : Type_Descr_Access;
|
|
Index : Type_Index;
|
|
begin
|
|
exit when Member = No_Type_Member;
|
|
|
|
if Member.Name /= No_Qualified_Name then
|
|
Lookup_Simple_Type
|
|
(Member.Name, Internal.Loc, Item, Index);
|
|
if Item.Final (Final_Union) then
|
|
Validation_Error
|
|
(Parser,
|
|
To_QName (Member.Name) & " is final for union",
|
|
Internal.Loc);
|
|
end if;
|
|
|
|
else
|
|
Create_Simple_Type (Member.Local, Item, Index);
|
|
end if;
|
|
|
|
Simple.Union (Index_In_Simple) := Item.Simple_Content;
|
|
Index_In_Simple := Index_In_Simple + 1;
|
|
end;
|
|
end loop;
|
|
|
|
Result := Create_Simple_Type (NFA, Simple);
|
|
Descr.Simple_Content := Result;
|
|
Descr.Restriction_Of := Any_Simple_Type_Index;
|
|
|
|
when Simple_Type_List =>
|
|
Simple := (Kind => Primitive_List,
|
|
List_Item => No_Simple_Type_Index,
|
|
others => <>);
|
|
|
|
for U in Internal.List_Items'Range loop
|
|
declare
|
|
Member : constant Type_Member := Internal.List_Items (U);
|
|
Item : Type_Descr_Access;
|
|
Index : Type_Index;
|
|
begin
|
|
exit when Member = No_Type_Member;
|
|
if Member.Name /= No_Qualified_Name then
|
|
Lookup_Simple_Type
|
|
(Member.Name, Internal.Loc, Item, Index);
|
|
if Item.Final (Final_List) then
|
|
Validation_Error
|
|
(Parser,
|
|
To_QName (Member.Name) & " is final for list",
|
|
Internal.Loc);
|
|
end if;
|
|
else
|
|
Create_Simple_Type (Member.Local, Item, Index);
|
|
end if;
|
|
|
|
Simple.List_Item := Item.Simple_Content;
|
|
end;
|
|
end loop;
|
|
|
|
Result := Create_Simple_Type (NFA, Simple);
|
|
Descr.Simple_Content := Result;
|
|
Descr.Restriction_Of := Any_Simple_Type_Index;
|
|
|
|
when Simple_Type_Restriction | Simple_Type_Extension =>
|
|
declare
|
|
Base : Simple_Type_Descr;
|
|
Error : Symbol;
|
|
Loc : Location;
|
|
NFA_Simple : Type_Descr_Access;
|
|
NFA_Type : Type_Index;
|
|
begin
|
|
if Internal.Base.Name /= No_Qualified_Name then
|
|
Lookup_Simple_Type
|
|
(Internal.Base.Name, Internal.Loc,
|
|
NFA_Simple, NFA_Type);
|
|
else
|
|
Create_Simple_Type
|
|
(Internal.Base.Local, NFA_Simple, NFA_Type);
|
|
end if;
|
|
|
|
if Internal.Base = No_Type_Member then
|
|
Base := Any_Simple_Type;
|
|
NFA_Type := Any_Simple_Type_Index;
|
|
|
|
elsif NFA_Simple = null
|
|
or else NFA_Simple.Simple_Content = No_Simple_Type_Index
|
|
then
|
|
Validation_Error
|
|
(Parser,
|
|
"base type specified in simpleContent definition must"
|
|
& " be a simple type",
|
|
Loc);
|
|
|
|
else
|
|
Base := Copy
|
|
(Get_Simple_Type (NFA, NFA_Simple.Simple_Content));
|
|
Override (Simple => Base,
|
|
Facets => Internal.Facets,
|
|
Symbols => Get_Symbol_Table (Parser.all),
|
|
As_Restriction => Internal.Kind =
|
|
Simple_Type_Restriction,
|
|
Error => Error,
|
|
Error_Loc => Loc);
|
|
if Error /= No_Symbol then
|
|
Validation_Error (Parser, Get (Error).all, Loc);
|
|
end if;
|
|
end if;
|
|
|
|
case Internal.Kind is
|
|
when Simple_Type_Restriction =>
|
|
Descr.Restriction_Of := NFA_Type;
|
|
when Simple_Type_Extension =>
|
|
Descr.Extension_Of := NFA_Type;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
|
|
Result := Create_Simple_Type (NFA, Base);
|
|
Descr.Simple_Content := Result;
|
|
end;
|
|
end case;
|
|
|
|
Info.Simple.In_Process := False;
|
|
end Create_Simple_Type;
|
|
|
|
------------------------------
|
|
-- Create_Global_Attributes --
|
|
------------------------------
|
|
|
|
procedure Create_Global_Attributes (Attr : Internal_Attribute_Descr) is
|
|
Attr2 : Internal_Attribute_Descr;
|
|
begin
|
|
pragma Assert (Attr.Ref = No_Qualified_Name,
|
|
"A global attribute cannot define ref");
|
|
pragma Assert (Attr.Descr.Name /= No_Qualified_Name,
|
|
"A global attribute must have a name");
|
|
pragma Assert (Attr.Any = No_Internal_Any_Descr,
|
|
"A global attribute is not <anyAttribute>");
|
|
pragma Assert (Attr.Descr.Next = Empty_Named_Attribute_List,
|
|
"Global attributes cannot be in a list");
|
|
pragma Assert (Attr.Descr.Simple_Type = No_Simple_Type_Index,
|
|
"Type of global attributes should be undefined here");
|
|
|
|
Attr2 := Attr;
|
|
Resolve_Attribute_Type (Attr2, No_Location);
|
|
|
|
Create_Global_Attribute (Parser, Attr2.Descr, No_Location);
|
|
end Create_Global_Attributes;
|
|
|
|
------------------
|
|
-- Process_Type --
|
|
------------------
|
|
|
|
procedure Process_Type (Info : in out Internal_Type_Descr) is
|
|
S1 : State;
|
|
List : Attributes_List := No_Attributes;
|
|
|
|
Processed_Groups : AttrGroup_HTables.Instance;
|
|
-- ??? If this table is here, we can't have an <extension> with the
|
|
-- same attributeGroup as its base type. Maybe this should be local
|
|
-- to Recursive_Add_Attributes instead
|
|
|
|
procedure Recursive_Add_Attributes (Info : Internal_Type_Descr);
|
|
procedure Recursive_Add_Attributes (Info : Internal_Type_Descr) is
|
|
Ty : Global_Reference;
|
|
Index : Internal_Type_Index;
|
|
Had_Any : Boolean := False;
|
|
Base : Qualified_Name;
|
|
As_Restriction : Boolean;
|
|
begin
|
|
if Info.Is_Simple then
|
|
-- A simpleType has no attribute
|
|
return;
|
|
elsif Info.Details = null then
|
|
Add_Attributes (List, Info.Attributes, Processed_Groups,
|
|
As_Restriction => True, Had_Any => Had_Any);
|
|
Reset (Processed_Groups);
|
|
return;
|
|
end if;
|
|
|
|
if Info.Details.Kind = Type_Extension then
|
|
Base := Info.Details.Extension.Base;
|
|
As_Restriction := False;
|
|
elsif Info.Details.Kind = Type_Restriction then
|
|
Base := Info.Details.Restriction.Base;
|
|
As_Restriction := True;
|
|
else
|
|
Base := No_Qualified_Name;
|
|
end if;
|
|
|
|
if Base = No_Qualified_Name then
|
|
-- No character data is allowed, but we might have attributes
|
|
Add_Attributes (List, Info.Attributes, Processed_Groups,
|
|
As_Restriction => True, Had_Any => Had_Any);
|
|
|
|
elsif not As_Restriction then
|
|
Ty := Get (Ref.all, (Base, Ref_Type));
|
|
if Ty = No_Global_Reference then
|
|
Validation_Error
|
|
(Parser, "No type """ & To_QName (Base) & """", Info.Loc);
|
|
end if;
|
|
|
|
-- If the base type is in the current package, we might not
|
|
-- have computed all its attributes. Otherwise, get the list of
|
|
-- attributes already computed in the grammar, since it is
|
|
-- complete.
|
|
|
|
Index := Get (Types, Base);
|
|
if Index /= No_Internal_Type_Index then
|
|
Recursive_Add_Attributes (Shared.Types.Table (Index));
|
|
else
|
|
Add_Attributes
|
|
(Parser, List,
|
|
Get_Type_Descr (NFA, Ty.Typ).Attributes,
|
|
As_Restriction => False, Loc => Info.Loc);
|
|
end if;
|
|
|
|
Add_Attributes (List, Info.Attributes,
|
|
Processed_Groups, As_Restriction => False,
|
|
Had_Any => Had_Any);
|
|
|
|
else
|
|
Ty := Get (Ref.all, (Base, Ref_Type));
|
|
if Ty = No_Global_Reference then
|
|
Validation_Error
|
|
(Parser, "No type """ & To_QName (Base) & """", Info.Loc);
|
|
end if;
|
|
|
|
Index := Get (Types, Base);
|
|
if Index /= No_Internal_Type_Index then
|
|
Recursive_Add_Attributes (Shared.Types.Table (Index));
|
|
else
|
|
Add_Attributes
|
|
(Parser, List,
|
|
Get_Type_Descr (NFA, Ty.Typ).Attributes,
|
|
As_Restriction => True, Loc => Info.Loc);
|
|
end if;
|
|
|
|
Had_Any := False;
|
|
Add_Attributes (List, Info.Attributes,
|
|
Processed_Groups, As_Restriction => True,
|
|
Had_Any => Had_Any);
|
|
|
|
-- Always add <anyAttribute>, even if none was given in the
|
|
-- restriction (in which case none should exist for the type
|
|
-- either);
|
|
|
|
if not Had_Any then
|
|
List.Any := No_Any_Descr; -- Nothing matches
|
|
end if;
|
|
end if;
|
|
end Recursive_Add_Attributes;
|
|
|
|
begin
|
|
if Info.Is_Simple then
|
|
null; -- Already done in Process_Type
|
|
else
|
|
if Debug then
|
|
Debug_Output ("Process complexType "
|
|
& To_QName (Info.Properties.Name));
|
|
end if;
|
|
|
|
declare
|
|
Descr : constant access Type_Descr :=
|
|
Get_Type_Descr (NFA, Info.In_NFA);
|
|
Mask : Visited_All_Children;
|
|
Start : State := Descr.Complex_Content;
|
|
Is_All : constant Boolean :=
|
|
Info.Details /= null and then Info.Details.Kind = Type_All;
|
|
begin
|
|
pragma Assert (Descr.Complex_Content /= No_State);
|
|
|
|
if Is_All and then Info.Details.Min_Occurs.Value = 0 then
|
|
-- See comment in Process_Details as to why this is
|
|
-- handled here.
|
|
-- We should not make the transition directly from the
|
|
-- start node (Descr.Complex_Content), because it would
|
|
-- mean a user can start a <all minOccurs="0"> and stop
|
|
-- in the middle with no error
|
|
|
|
Start := NFA.Add_State;
|
|
NFA.Add_Empty_Transition (Descr.Complex_Content, Start);
|
|
end if;
|
|
|
|
Process_Details
|
|
(In_Type => Descr,
|
|
Details => Info.Details,
|
|
Start => Start, -- Descr.Complex_Content,
|
|
From => Start,
|
|
Nested_End => S1,
|
|
Mask => Mask);
|
|
|
|
-- Add the attributes only after we did the details, so that we
|
|
-- know there is no infinite recursion between the base types
|
|
-- of extensions and restrictions
|
|
|
|
if Debug then
|
|
Debug_Output ("Process attributes for complexType "
|
|
& To_QName (Info.Properties.Name) & " State="
|
|
& Descr.Complex_Content'Img
|
|
& " type_index=" & Info.In_NFA'Img);
|
|
end if;
|
|
|
|
Recursive_Add_Attributes (Info);
|
|
Descr.Attributes := List;
|
|
|
|
if Is_All then
|
|
NFA.Add_Transition
|
|
(S1, Final_State,
|
|
(Kind => Transition_Close_From_All,
|
|
Mask => Mask));
|
|
|
|
if Info.Details.Min_Occurs.Value = 0 then
|
|
NFA.Add_Transition
|
|
(Descr.Complex_Content, Final_State,
|
|
(Kind => Transition_Close));
|
|
end if;
|
|
|
|
else
|
|
NFA.Add_Transition
|
|
(S1, Final_State, (Kind => Transition_Close));
|
|
end if;
|
|
end;
|
|
end if;
|
|
|
|
Reset (Processed_Groups);
|
|
|
|
exception
|
|
when others =>
|
|
Reset (Processed_Groups);
|
|
raise;
|
|
end Process_Type;
|
|
|
|
Element_Info : Element_Descr;
|
|
Attr : Internal_Attribute_Descr;
|
|
S : State;
|
|
|
|
Ignored : Type_Descr_Access;
|
|
Ignored_Index : Type_Index;
|
|
pragma Unreferenced (Ignored, Ignored_Index);
|
|
|
|
begin
|
|
if Debug then
|
|
Debug_Output ("Create_NFA");
|
|
end if;
|
|
|
|
-- Prepare the entries for the types. These are empty to start with, but
|
|
-- they are needed to be able to create the more complex types, and the
|
|
-- global element.
|
|
|
|
for J in Type_Tables.First .. Last (Shared.Types) loop
|
|
-- Create the empty nested NFA if needed
|
|
|
|
S := No_State;
|
|
|
|
if not Shared.Types.Table (J).Is_Simple then
|
|
S := NFA.Add_State;
|
|
Shared.Types.Table (J).Properties.Complex_Content := S;
|
|
if Debug then
|
|
Debug_Output
|
|
("Created state for complexContent "
|
|
& To_QName (Shared.Types.Table (J).Properties.Name)
|
|
& " type=" & J'Img & " state=" & S'Img);
|
|
end if;
|
|
end if;
|
|
|
|
Shared.Types.Table (J).In_NFA :=
|
|
Create_Type (NFA, Shared.Types.Table (J).Properties);
|
|
|
|
if S /= No_State then
|
|
-- At least .Complex_Content has changed, so we need to reset data
|
|
NFA.Set_Data
|
|
(S,
|
|
State_Data'
|
|
(Simple => Shared.Types.Table (J).In_NFA,
|
|
Block => No_Block,
|
|
Nillable => False,
|
|
Default => No_Symbol,
|
|
Fixed => No_Symbol));
|
|
end if;
|
|
|
|
if Shared.Types.Table (J).Properties.Name /= No_Qualified_Name then
|
|
Set (Types, Shared.Types.Table (J).Properties.Name, J);
|
|
end if;
|
|
end loop;
|
|
|
|
-- Process the simple types (must be in a separate loop, since a
|
|
-- restriction or a union needs to know about its base type)
|
|
|
|
for J in Type_Tables.First .. Last (Shared.Types) loop
|
|
Create_Simple_Type (J, Ignored, Ignored_Index);
|
|
end loop;
|
|
|
|
-- Prepare the entries for the global attributes
|
|
|
|
Attr := Get_First (Shared.Global_Attributes);
|
|
while Attr /= No_Internal_Attribute loop
|
|
Create_Global_Attributes (Attr);
|
|
Attr := Get_Next (Shared.Global_Attributes);
|
|
end loop;
|
|
|
|
-- Prepare schema for global elements
|
|
|
|
if Debug then
|
|
Debug_Output ("Create_NFA: adding global elements");
|
|
end if;
|
|
|
|
Element_Info := Get_First (Shared.Global_Elements);
|
|
while Element_Info /= No_Element_Descr loop
|
|
Process_Global_Element (Element_Info, Start_State);
|
|
|
|
-- Save the state
|
|
Set (Shared.Global_Elements, Element_Info.Name, Element_Info);
|
|
|
|
Element_Info := Get_Next (Shared.Global_Elements);
|
|
end loop;
|
|
|
|
if Debug then
|
|
Debug_Output ("Create_NFA: complete type definition");
|
|
end if;
|
|
|
|
-- Finally, complete the definition of complexTypes
|
|
|
|
for J in Type_Tables.First .. Last (Shared.Types) loop
|
|
Process_Type (Shared.Types.Table (J));
|
|
end loop;
|
|
|
|
if Debug then
|
|
Output_Action ("NFA: " & Dump_Dot_NFA (Get_Grammar (Parser.all)));
|
|
end if;
|
|
|
|
Reset (Types);
|
|
|
|
exception
|
|
when others =>
|
|
Reset (Types);
|
|
raise;
|
|
end Create_NFA;
|
|
|
|
----------
|
|
-- Free --
|
|
----------
|
|
|
|
procedure Free (Shared : in out XSD_Data_Access) is
|
|
procedure Unchecked_Free is new Ada.Unchecked_Deallocation
|
|
(XSD_Data, XSD_Data_Access);
|
|
Attr : AttrGroup_Descr;
|
|
Gr : Group_Descr;
|
|
begin
|
|
if Shared /= null then
|
|
|
|
-- Free all data structures, no longer needed
|
|
|
|
Reset (Shared.Global_Elements);
|
|
|
|
Gr := Get_First (Shared.Global_Groups);
|
|
while Gr /= No_Group_Descr loop
|
|
Free (Gr.Details);
|
|
Gr := Get_Next (Shared.Global_Groups);
|
|
end loop;
|
|
Reset (Shared.Global_Groups);
|
|
|
|
Attr := Get_First (Shared.Global_AttrGroups);
|
|
while Attr /= No_AttrGroup_Descr loop
|
|
Unchecked_Free (Attr.Attributes);
|
|
Attr := Get_Next (Shared.Global_AttrGroups);
|
|
end loop;
|
|
Reset (Shared.Global_AttrGroups);
|
|
|
|
for T in Type_Tables.First .. Last (Shared.Types) loop
|
|
if Shared.Types.Table (T).Is_Simple then
|
|
null;
|
|
else
|
|
Unchecked_Free (Shared.Types.Table (T).Attributes);
|
|
Free (Shared.Types.Table (T).Details);
|
|
end if;
|
|
end loop;
|
|
Free (Shared.Types);
|
|
|
|
Reset (Shared.Global_Attributes);
|
|
|
|
Unchecked_Free (Shared);
|
|
end if;
|
|
end Free;
|
|
|
|
-----------------------------
|
|
-- Parse_Grammar_If_Needed --
|
|
-----------------------------
|
|
|
|
procedure Parse_Grammar_If_Needed
|
|
(Handler : not null access Validating_Reader'Class;
|
|
URI : Symbol;
|
|
Xsd_File : Symbol;
|
|
Do_Create_NFA : Boolean)
|
|
is
|
|
File : File_Input;
|
|
Schema : Schema_Reader;
|
|
S_File_Full : constant Symbol := To_Absolute_URI (Handler.all, Xsd_File);
|
|
Need_To_Initialize : Boolean := True;
|
|
begin
|
|
GNAT.Task_Lock.Lock;
|
|
Set_XML_Version (Schema, Get_XML_Version (Handler.all));
|
|
if URI_Was_Parsed (Get_Grammar (Handler.all), S_File_Full) then
|
|
if Debug then
|
|
Debug_Output ("Parse_Grammar " & Get (S_File_Full).all
|
|
& " already parsed");
|
|
end if;
|
|
GNAT.Task_Lock.Unlock;
|
|
return;
|
|
end if;
|
|
|
|
if Debug then
|
|
Debug_Output ("Parse_Grammar NS={" & Get (URI).all
|
|
& "} XSD={" & Get (Xsd_File).all & "} "
|
|
& Get (S_File_Full).all);
|
|
end if;
|
|
|
|
if Get_XSD_Version (Handler.Grammar) = XSD_1_0 then
|
|
-- Must check that no element of the same namespace was seen
|
|
-- already (as per 4.3.2 (4) in the XSD 1.0 norm, which was
|
|
-- changed in XSD 1.1).
|
|
|
|
declare
|
|
NS : XML_NS;
|
|
begin
|
|
Find_NS_From_URI
|
|
(Handler.all,
|
|
URI => URI,
|
|
NS => NS);
|
|
|
|
if NS /= No_XML_NS
|
|
and then Element_Count (NS) > 0
|
|
and then S_File_Full /= Get_System_Id (NS)
|
|
and then Get_Feature
|
|
(Handler.all, Sax.Readers.Schema_Validation_Feature)
|
|
then
|
|
Validation_Error
|
|
(Handler,
|
|
"schemaLocation for """
|
|
& Get (URI).all
|
|
& """ cannot occur after the first"
|
|
& " element of that namespace in XSD 1.0");
|
|
end if;
|
|
end;
|
|
end if;
|
|
|
|
if Debug then
|
|
Output_Seen ("Parsing grammar: " & Get (S_File_Full).all);
|
|
end if;
|
|
|
|
Open (Get (S_File_Full).all, File);
|
|
Set_Public_Id (File, Get (S_File_Full).all);
|
|
Set_System_Id (File, Get (S_File_Full).all);
|
|
|
|
-- Add_To will likely already contain the grammar for the
|
|
-- schema-for-schema, and we won't have to recreate it in most cases.
|
|
|
|
Set_Symbol_Table (Schema, Get_Symbol_Table (Handler.all));
|
|
Set_Grammar (Schema, Handler.Grammar);
|
|
Use_Basename_In_Error_Messages
|
|
(Schema, Use_Basename_In_Error_Messages (Handler.all));
|
|
|
|
Set_Feature
|
|
(Schema,
|
|
Sax.Readers.Schema_Validation_Feature,
|
|
Get_Feature (Handler.all, Sax.Readers.Schema_Validation_Feature));
|
|
|
|
if Handler.all in Schema_Reader'Class then
|
|
Schema.Shared := Schema_Reader (Handler.all).Shared;
|
|
Need_To_Initialize := False;
|
|
end if;
|
|
|
|
begin
|
|
Internal_Parse
|
|
(Schema, File,
|
|
Default_Namespace => URI,
|
|
Do_Initialize_Shared => Need_To_Initialize,
|
|
Do_Create_NFA => Need_To_Initialize and Do_Create_NFA);
|
|
exception
|
|
when XML_Not_Implemented | XML_Validation_Error =>
|
|
-- Copy the error message and location from Schema to Handler
|
|
Close (File);
|
|
Handler.Error_Msg := Schema.Error_Msg;
|
|
Handler.Error_Location := Schema.Error_Location;
|
|
raise;
|
|
end;
|
|
|
|
Free (Schema);
|
|
Close (File);
|
|
|
|
if Debug then
|
|
Output_Seen ("Done parsing new grammar: " & Get (Xsd_File).all);
|
|
end if;
|
|
|
|
GNAT.Task_Lock.Unlock;
|
|
|
|
exception
|
|
when Ada.IO_Exceptions.Name_Error =>
|
|
Free (Schema);
|
|
Close (File);
|
|
GNAT.Task_Lock.Unlock;
|
|
|
|
if Debug then
|
|
Debug_Output
|
|
(ASCII.LF
|
|
& "!!!! Could not open file " & Get (S_File_Full).all
|
|
& ASCII.LF);
|
|
end if;
|
|
|
|
-- According to XML Schema Primer 0, section 5.6, this is not an
|
|
-- error when we do not find the schema, since this attribute is only
|
|
-- a hint.
|
|
Warning
|
|
(Handler.all,
|
|
Create (Message => "Could not open file " & Get (S_File_Full).all,
|
|
Loc => Handler.Current_Location));
|
|
|
|
when others =>
|
|
GNAT.Task_Lock.Unlock;
|
|
Close (File);
|
|
raise;
|
|
end Parse_Grammar_If_Needed;
|
|
|
|
--------------------
|
|
-- Internal_Parse --
|
|
--------------------
|
|
|
|
procedure Internal_Parse
|
|
(Parser : in out Schema_Reader;
|
|
Input : in out Input_Sources.Input_Source'Class;
|
|
Default_Namespace : Symbol;
|
|
Do_Create_NFA : Boolean;
|
|
Do_Initialize_Shared : Boolean)
|
|
is
|
|
Grammar : constant XML_Grammar := Get_Grammar (Parser);
|
|
URI : Symbol;
|
|
begin
|
|
if Debug then
|
|
Output_Action
|
|
("Parsing schema " & Input_Sources.Get_System_Id (Input));
|
|
end if;
|
|
|
|
Initialize_Symbols (Parser);
|
|
|
|
URI := Find_Symbol (Parser, Input_Sources.Get_System_Id (Input));
|
|
|
|
if not URI_Was_Parsed (Grammar, URI) then
|
|
|
|
if Do_Initialize_Shared then
|
|
Parser.Shared := new XSD_Data;
|
|
Init (Parser.Shared.Types);
|
|
end if;
|
|
|
|
Initialize_Grammar (Parser);
|
|
|
|
Parser.Target_NS := Default_Namespace;
|
|
|
|
Set_Grammar (Parser, Grammar); -- In case it was not initialized yet
|
|
Set_Parsed_URI (Parser, URI);
|
|
|
|
Schema.Readers.Parse (Validating_Reader (Parser), Input);
|
|
|
|
if Do_Create_NFA then
|
|
Create_NFA (Parser'Access);
|
|
end if;
|
|
|
|
if Do_Initialize_Shared then
|
|
Free (Parser.Shared);
|
|
end if;
|
|
|
|
Unchecked_Free (Parser.Contexts);
|
|
end if;
|
|
|
|
exception
|
|
when others =>
|
|
Unchecked_Free (Parser.Contexts);
|
|
|
|
if Do_Initialize_Shared then
|
|
Free (Parser.Shared);
|
|
end if;
|
|
|
|
raise;
|
|
end Internal_Parse;
|
|
|
|
-----------
|
|
-- Parse --
|
|
-----------
|
|
|
|
procedure Parse
|
|
(Parser : in out Schema_Reader;
|
|
Input : in out Input_Sources.Input_Source'Class) is
|
|
begin
|
|
Internal_Parse
|
|
(Parser,
|
|
Input,
|
|
Default_Namespace => Empty_String,
|
|
Do_Create_NFA => True,
|
|
Do_Initialize_Shared => True);
|
|
end Parse;
|
|
|
|
-------------------
|
|
-- Resolve_QName --
|
|
-------------------
|
|
|
|
function Resolve_QName
|
|
(Handler : access Schema_Reader'Class;
|
|
QName : Sax.Symbols.Symbol;
|
|
NS_If_Empty : Sax.Symbols.Symbol := Empty_String;
|
|
Loc : Location) return Qualified_Name
|
|
is
|
|
Val : Cst_Byte_Sequence_Access;
|
|
Separator : Integer;
|
|
NS : XML_NS;
|
|
Prefix : Symbol;
|
|
begin
|
|
if QName = No_Symbol then
|
|
return No_Qualified_Name;
|
|
else
|
|
Val := Get (QName);
|
|
Separator := Split_Qname (Val.all);
|
|
|
|
Prefix :=
|
|
Find_Symbol (Handler.all, Val (Val'First .. Separator - 1));
|
|
Get_Namespace_From_Prefix
|
|
(Handler => Handler.all,
|
|
Prefix => Prefix,
|
|
NS => NS);
|
|
|
|
if NS = No_XML_NS then
|
|
if Prefix /= Empty_String then
|
|
Validation_Error
|
|
(Handler,
|
|
"Cannot resolve namespace prefix "
|
|
& Val (Val'First .. Separator - 1),
|
|
Loc);
|
|
return No_Qualified_Name;
|
|
else
|
|
return
|
|
(NS => NS_If_Empty,
|
|
Local =>
|
|
Find_Symbol (Handler.all, Val (Separator + 1 .. Val'Last)));
|
|
end if;
|
|
|
|
else
|
|
return
|
|
(NS => Get_URI (NS),
|
|
Local =>
|
|
Find_Symbol (Handler.all, Val (Separator + 1 .. Val'Last)));
|
|
end if;
|
|
end if;
|
|
end Resolve_QName;
|
|
|
|
----------------
|
|
-- Get_Occurs --
|
|
----------------
|
|
|
|
procedure Get_Occurs
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List;
|
|
Min_Occurs, Max_Occurs : out Occurrences)
|
|
is
|
|
Min_Occurs_Index : constant Integer :=
|
|
Get_Index (Atts, URI => Empty_String, Local_Name => Handler.MinOccurs);
|
|
Max_Occurs_Index : constant Integer :=
|
|
Get_Index (Atts, URI => Empty_String, Local_Name => Handler.MaxOccurs);
|
|
|
|
function Occurs_From_Value (Index : Integer) return Occurrences;
|
|
-- Return the value of maxOccurs from the attributes'value. This
|
|
-- properly takes into account the "unbounded" case
|
|
|
|
function Occurs_From_Value (Index : Integer) return Occurrences is
|
|
Value : constant Symbol := Get_Value (Atts, Index);
|
|
begin
|
|
if Value = Handler.Unbounded then
|
|
return (Unbounded => True);
|
|
else
|
|
declare
|
|
Val : constant Cst_Byte_Sequence_Access := Get (Value);
|
|
Pos : Integer;
|
|
C : Unicode_Char;
|
|
begin
|
|
return (Unbounded => False, Value => Natural'Value (Val.all));
|
|
exception
|
|
when Constraint_Error =>
|
|
-- Either we have an integer too big to fit in Integer, or
|
|
-- we do not have an integer at all
|
|
Pos := Val'First;
|
|
while Pos <= Val'Last loop
|
|
Encoding.Read (Val.all, Pos, C);
|
|
if not Is_Digit (C) then
|
|
Validation_Error
|
|
(Handler, "Value for ""maxOccurs"" must"
|
|
& " be an integer or ""unbounded""");
|
|
end if;
|
|
end loop;
|
|
|
|
return (Unbounded => False, Value => Natural'Last);
|
|
end;
|
|
end if;
|
|
end Occurs_From_Value;
|
|
|
|
begin
|
|
Min_Occurs := (False, 1);
|
|
Max_Occurs := (False, 1);
|
|
|
|
if Min_Occurs_Index /= -1 then
|
|
Min_Occurs := Occurs_From_Value (Min_Occurs_Index);
|
|
if Min_Occurs.Unbounded then
|
|
Validation_Error
|
|
(Handler, "minOccurs cannot be ""unbounded""");
|
|
end if;
|
|
end if;
|
|
|
|
if Max_Occurs_Index /= -1 then
|
|
Max_Occurs := Occurs_From_Value (Max_Occurs_Index);
|
|
end if;
|
|
|
|
if not Max_Occurs.Unbounded then
|
|
if Max_Occurs.Value > Max_Max_Occurs then
|
|
Validation_Error
|
|
(Handler,
|
|
"maxOccurs is too big (XML/Ada supports up to"
|
|
& Max_Max_Occurs'Img & "), consider using ""unbounded""",
|
|
Except => XML_Limitation'Identity);
|
|
|
|
elsif Max_Occurs.Value > Max_Occurs_Warn then
|
|
Handler.Warning
|
|
(Create
|
|
(Message =>
|
|
"maxOccurs is big and could result in a very large state"
|
|
& " machine. Consider using ""unbounded"" instead",
|
|
Loc => Handler.Current_Location));
|
|
end if;
|
|
end if;
|
|
end Get_Occurs;
|
|
|
|
------------------
|
|
-- Push_Context --
|
|
------------------
|
|
|
|
procedure Push_Context
|
|
(Handler : access Schema_Reader'Class; Ctx : Context)
|
|
is
|
|
Tmp : Context_Array_Access;
|
|
begin
|
|
if Handler.Contexts_Last = 0 then
|
|
Handler.Contexts := new Context_Array (1 .. Default_Contexts);
|
|
elsif Handler.Contexts_Last = Handler.Contexts'Last then
|
|
Tmp := new Context_Array (1 .. Handler.Contexts'Last + 30);
|
|
Tmp (Handler.Contexts'Range) := Handler.Contexts.all;
|
|
Unchecked_Free (Handler.Contexts);
|
|
Handler.Contexts := Tmp;
|
|
end if;
|
|
|
|
Handler.Contexts_Last := Handler.Contexts_Last + 1;
|
|
Handler.Contexts (Handler.Contexts_Last) := Ctx;
|
|
end Push_Context;
|
|
|
|
------------------
|
|
-- Create_Group --
|
|
------------------
|
|
|
|
procedure Create_Group
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Min_Occurs, Max_Occurs : Occurrences := (False, 1);
|
|
Group : Group_Descr;
|
|
Name : Qualified_Name;
|
|
Details : Type_Details_Access;
|
|
begin
|
|
Group.Loc := Handler.Current_Location;
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Name then
|
|
Group.Name := (NS => Handler.Target_NS,
|
|
Local => Get_Value (Atts, J));
|
|
elsif Name.Local = Handler.Ref then
|
|
Group.Ref := Resolve_QName
|
|
(Handler, Get_Value (Atts, J),
|
|
Loc => Get_Location (Atts, J));
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
case Handler.Contexts (Handler.Contexts_Last).Typ is
|
|
when Context_Schema | Context_Redefine =>
|
|
null;
|
|
|
|
when Context_Sequence | Context_Choice | Context_Extension
|
|
| Context_Restriction =>
|
|
Get_Occurs (Handler, Atts, Min_Occurs, Max_Occurs);
|
|
Details := new Type_Details'
|
|
(Kind => Type_Group,
|
|
Min_Occurs => Min_Occurs,
|
|
Max_Occurs => Max_Occurs,
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
Group => Group);
|
|
Insert_In_Type (Handler, Details);
|
|
|
|
when others =>
|
|
Validation_Error
|
|
(Handler,
|
|
"Unsupported ""group"" in this context",
|
|
Except => XML_Not_Implemented'Identity);
|
|
end case;
|
|
|
|
Push_Context (Handler,
|
|
(Typ => Context_Group,
|
|
Group => Group));
|
|
|
|
end Create_Group;
|
|
|
|
------------------
|
|
-- Finish_Group --
|
|
------------------
|
|
|
|
procedure Finish_Group (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
begin
|
|
case Next.Typ is
|
|
when Context_Schema | Context_Redefine =>
|
|
Set (Handler.Shared.Global_Groups, Ctx.Group.Name, Ctx.Group);
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end Finish_Group;
|
|
|
|
----------------------------
|
|
-- Create_Attribute_Group --
|
|
----------------------------
|
|
|
|
procedure Create_Attribute_Group
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Group : AttrGroup_Descr;
|
|
Name : Qualified_Name;
|
|
begin
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Name then
|
|
Group.Name := (NS => Handler.Target_NS,
|
|
Local => Get_Value (Atts, J));
|
|
elsif Name.Local = Handler.Ref then
|
|
Group.Ref := Resolve_QName
|
|
(Handler, Get_Value (Atts, J),
|
|
Loc => Get_Location (Atts, J));
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
Push_Context
|
|
(Handler, (Typ => Context_Attribute_Group,
|
|
Attr_Group => Group));
|
|
end Create_Attribute_Group;
|
|
|
|
----------------------------
|
|
-- Finish_Attribute_Group --
|
|
----------------------------
|
|
|
|
procedure Finish_Attribute_Group (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
Ctx2 : Context_Access;
|
|
Index : Natural;
|
|
begin
|
|
case Next.Typ is
|
|
when Context_Schema | Context_Redefine =>
|
|
Set
|
|
(Handler.Shared.Global_AttrGroups,
|
|
Ctx.Attr_Group.Name, Ctx.Attr_Group);
|
|
when Context_Type_Def =>
|
|
pragma Assert (Ctx.Attr_Group.Attributes = null);
|
|
Append
|
|
(Handler.Shared.Types.Table (Next.Type_Info).Attributes,
|
|
(Kind => Kind_Group,
|
|
Loc => Handler.Current_Location,
|
|
Group_Ref => Ctx.Attr_Group.Ref));
|
|
when Context_Extension | Context_Simple_Extension =>
|
|
pragma Assert (Ctx.Attr_Group.Attributes = null);
|
|
Index := Handler.Contexts_Last - 1;
|
|
while Index >= Handler.Contexts'First loop
|
|
Ctx2 := Handler.Contexts (Index)'Access;
|
|
if Ctx2.Typ = Context_Type_Def then
|
|
Append
|
|
(Handler.Shared.Types.Table (Ctx2.Type_Info).Attributes,
|
|
(Kind => Kind_Group,
|
|
Loc => Handler.Current_Location,
|
|
Group_Ref => Ctx.Attr_Group.Ref));
|
|
exit;
|
|
end if;
|
|
|
|
Index := Index - 1;
|
|
end loop;
|
|
when Context_Attribute_Group =>
|
|
pragma Assert (Ctx.Attr_Group.Attributes = null);
|
|
Append
|
|
(Next.Attr_Group.Attributes,
|
|
(Kind => Kind_Group,
|
|
Loc => Handler.Current_Location,
|
|
Group_Ref => Ctx.Attr_Group.Ref));
|
|
|
|
when others =>
|
|
Unchecked_Free (Ctx.Attr_Group.Attributes);
|
|
Validation_Error
|
|
(Handler,
|
|
"Invalid context for attributeGroup: " & Next.Typ'Img,
|
|
Except => XML_Not_Implemented'Identity);
|
|
end case;
|
|
end Finish_Attribute_Group;
|
|
|
|
------------
|
|
-- Append --
|
|
------------
|
|
|
|
procedure Append (List : in out Attr_Array_Access; Attr : Attr_Descr) is
|
|
Tmp : Attr_Array_Access;
|
|
begin
|
|
if List = null then
|
|
List := new Attr_Array'(1 => Attr,
|
|
2 .. 10 => (Kind => Kind_Unset,
|
|
Loc => No_Location));
|
|
|
|
elsif List (List'Last).Kind /= Kind_Unset then
|
|
Tmp := new Attr_Array (1 .. List'Last + 10);
|
|
Tmp (List'Range) := List.all;
|
|
Tmp (List'Last + 1) := Attr;
|
|
Tmp (List'Last + 2 .. Tmp'Last) :=
|
|
(others => Attr_Descr'(Kind => Kind_Unset, Loc => No_Location));
|
|
Unchecked_Free (List);
|
|
List := Tmp;
|
|
|
|
else
|
|
for L in List'Range loop
|
|
if List (L).Kind = Kind_Unset then
|
|
List (L) := Attr;
|
|
return;
|
|
end if;
|
|
end loop;
|
|
end if;
|
|
end Append;
|
|
|
|
--------------------
|
|
-- Create_Include --
|
|
--------------------
|
|
|
|
procedure Create_Include
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Schema_Location_Index : constant Integer :=
|
|
Get_Index (Atts, Empty_String, Handler.Schema_Location);
|
|
begin
|
|
Parse_Grammar
|
|
(Handler,
|
|
URI => Handler.Target_NS,
|
|
Xsd_File => Get_Value (Atts, Schema_Location_Index),
|
|
Do_Create_NFA => False); -- Will be performed later
|
|
end Create_Include;
|
|
|
|
---------------------
|
|
-- Create_Redefine --
|
|
---------------------
|
|
|
|
procedure Create_Redefine
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Location_Index : constant Integer :=
|
|
Get_Index (Atts, Empty_String, Handler.Schema_Location);
|
|
begin
|
|
-- Disable for now.
|
|
-- On the test./testschema -xsd boeingData/ipo4/ipo.xsd
|
|
-- -xsd boeingData/ipo4/address.xsd
|
|
-- -xsd boeingData/ipo4/itematt.xsd
|
|
-- boeingData/ipo4/ipo_1.xml
|
|
-- we redefine an extension whose base type comes from the redefined
|
|
-- grammar, and whose name is the same. As a result, the extension and
|
|
-- its base type end up being the same XML_Type, and thus we get
|
|
-- infinite loops. We should really merge the models when the grammar is
|
|
-- parsed.
|
|
|
|
Validation_Error
|
|
(Handler,
|
|
"<redefine> not supported",
|
|
Except => XML_Not_Implemented'Identity);
|
|
Parse_Grammar
|
|
(Handler,
|
|
URI => Handler.Target_NS,
|
|
Do_Create_NFA => True,
|
|
Xsd_File => Get_Value (Atts, Location_Index));
|
|
|
|
Push_Context (Handler, (Typ => Context_Redefine));
|
|
end Create_Redefine;
|
|
|
|
-------------------
|
|
-- Create_Import --
|
|
-------------------
|
|
|
|
procedure Create_Import
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Location_Index : constant Integer :=
|
|
Get_Index (Atts, Empty_String, Handler.Schema_Location);
|
|
-- Namespace_Index : constant Integer :=
|
|
-- Get_Index (Atts, Empty_String, Handler.Namespace);
|
|
begin
|
|
if Location_Index = -1 then
|
|
-- if Namespace_Index = -1 then
|
|
-- -- See 4.2.6.1: If that attribute is absent, then the import
|
|
-- -- allows unqualified reference to components with no target
|
|
-- -- namespace
|
|
-- null;
|
|
-- end if;
|
|
|
|
Validation_Error
|
|
(Handler,
|
|
"Import with no schemaLocation is unsupported",
|
|
Except => XML_Not_Implemented'Identity);
|
|
|
|
else
|
|
declare
|
|
Location : constant Symbol := Get_Value (Atts, Location_Index);
|
|
begin
|
|
if Debug then
|
|
Debug_Output ("Import: " & Get (Location).all);
|
|
Debug_Output ("Adding new grammar to Handler.Created_Grammar");
|
|
end if;
|
|
|
|
-- The namespace attribute indicates that the XSD may contain
|
|
-- qualified references to schema components in that namespace.
|
|
-- (4.2.6.1). It does not give the default targetNamespace
|
|
|
|
Parse_Grammar
|
|
(Handler,
|
|
URI => Empty_String,
|
|
Do_Create_NFA => True,
|
|
Xsd_File => Location);
|
|
end;
|
|
end if;
|
|
end Create_Import;
|
|
|
|
--------------------------
|
|
-- Create_Any_Attribute --
|
|
--------------------------
|
|
|
|
procedure Create_Any_Attribute
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Name : Qualified_Name;
|
|
Att : Attr_Descr (Kind => Kind_Attribute);
|
|
begin
|
|
Att.Loc := Handler.Current_Location;
|
|
Att.Attr.Any := (Namespaces => Handler.Any_Namespace,
|
|
Target_NS => Handler.Target_NS,
|
|
Process_Contents => Process_Strict);
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Namespace then
|
|
Att.Attr.Any.Namespaces := Get_Value (Atts, J);
|
|
elsif Name.Local = Handler.Process_Contents then
|
|
Att.Attr.Any.Process_Contents :=
|
|
Process_Contents_From_Atts (Handler, Atts, J);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
Insert_Attribute (Handler, Handler.Contexts_Last, Att);
|
|
end Create_Any_Attribute;
|
|
|
|
---------------------
|
|
-- Create_Notation --
|
|
---------------------
|
|
|
|
procedure Create_Notation
|
|
(Handler : access Schema_Reader'Class; Atts : Sax_Attribute_List)
|
|
is
|
|
type Notation_Descr is record
|
|
Name : Symbol;
|
|
System_Id : Symbol := Empty_String;
|
|
Public_Id : Symbol := Empty_String;
|
|
end record;
|
|
|
|
Name : Qualified_Name;
|
|
Notation : Notation_Descr;
|
|
|
|
begin
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Name then
|
|
Notation.Name := Get_Value (Atts, J);
|
|
elsif Name.Local = Handler.Public then
|
|
Notation.Public_Id := Get_Value (Atts, J);
|
|
elsif Name.Local = Handler.System then
|
|
Notation.System_Id := Get_Value (Atts, J);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
Add_Notation (Get_NFA (Handler.Grammar), Notation.Name);
|
|
Notation_Decl
|
|
(Sax_Reader'Class (Handler.all),
|
|
Name => Get (Notation.Name).all,
|
|
System_Id => Get (Notation.System_Id).all,
|
|
Public_Id => Get (Notation.Public_Id).all);
|
|
end Create_Notation;
|
|
|
|
--------------------
|
|
-- Create_Element --
|
|
--------------------
|
|
|
|
procedure Create_Element
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Min_Occurs, Max_Occurs : Occurrences := (False, 1);
|
|
Info : Element_Descr;
|
|
Name : Qualified_Name;
|
|
Details : Type_Details_Access;
|
|
|
|
begin
|
|
Info.Loc := Handler.Current_Location;
|
|
Info.Form := Handler.Element_Form_Default;
|
|
Info.Block := Handler.Target_Block_Default;
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Typ then
|
|
Info.Typ := Resolve_QName
|
|
(Handler, Get_Value (Atts, J),
|
|
NS_If_Empty => Handler.Target_NS,
|
|
Loc => Get_Location (Atts, J));
|
|
elsif Name.Local = Handler.Name then
|
|
Info.Name := (NS => Handler.Target_NS,
|
|
Local => Get_Value (Atts, J));
|
|
elsif Name.Local = Handler.Ref then
|
|
Info.Ref := Resolve_QName
|
|
(Handler, Get_Value (Atts, J),
|
|
Loc => Get_Location (Atts, J));
|
|
elsif Name.Local = Handler.Substitution_Group then
|
|
Info.Substitution_Group :=
|
|
Resolve_QName
|
|
(Handler, Get_Value (Atts, J),
|
|
Loc => Get_Location (Atts, J));
|
|
elsif Name.Local = Handler.Default then
|
|
Info.Default := Get_Value (Atts, J);
|
|
elsif Name.Local = Handler.Fixed then
|
|
Info.Fixed := Get_Value (Atts, J);
|
|
elsif Name.Local = Handler.S_Abstract then
|
|
Info.Is_Abstract := Get_Value_As_Boolean (Atts, J, False);
|
|
elsif Name.Local = Handler.Nillable then
|
|
Info.Nillable := Get_Value_As_Boolean (Atts, J, False);
|
|
elsif Name.Local = Handler.Form then
|
|
Info.Form := Compute_Form (Atts, Handler, J);
|
|
elsif Name.Local = Handler.Final then
|
|
Info.Final := Compute_Final (Atts, Handler, J);
|
|
elsif Name.Local = Handler.Block then
|
|
Compute_Blocks (Atts, Handler, Info.Block, Info.Has_Block, J);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
if Info.Name /= No_Qualified_Name then
|
|
if Info.Ref /= No_Qualified_Name
|
|
and then Info.Ref.NS = No_Symbol
|
|
and then Info.Name = Info.Ref
|
|
and then not In_Redefine_Context (Handler.all)
|
|
then
|
|
Validation_Error
|
|
(Handler, """ref"" attribute cannot be self-referencing");
|
|
|
|
elsif Info.Ref /= No_Qualified_Name then
|
|
Validation_Error
|
|
(Handler, "Name and Ref cannot be both specified");
|
|
end if;
|
|
|
|
elsif Info.Ref = No_Qualified_Name then
|
|
Validation_Error
|
|
(Handler, "Either ""name"" or ""ref"" attribute must be present");
|
|
|
|
else
|
|
-- Section 3.3.2, validity constraints 3.3.3
|
|
if Info.Typ /= No_Qualified_Name then
|
|
Validation_Error
|
|
(Handler,
|
|
"""type"" attribute cannot be specified along with ""ref""");
|
|
end if;
|
|
end if;
|
|
|
|
if Info.Default /= No_Symbol and then Info.Fixed /= No_Symbol then
|
|
Validation_Error
|
|
(Handler, "Default and Fixed cannot be both specified");
|
|
end if;
|
|
|
|
if Info.Ref /= No_Qualified_Name then
|
|
Info.Form := Qualified;
|
|
end if;
|
|
|
|
if Handler.Contexts (Handler.Contexts_Last).Typ /= Context_Schema then
|
|
Get_Occurs (Handler, Atts, Min_Occurs, Max_Occurs);
|
|
Details := new Type_Details'
|
|
(Kind => Type_Element,
|
|
Min_Occurs => Min_Occurs,
|
|
Max_Occurs => Max_Occurs,
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
Element => Info);
|
|
Insert_In_Type (Handler, Details);
|
|
end if;
|
|
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Element,
|
|
Elem_Details => Details,
|
|
Element => Info));
|
|
end Create_Element;
|
|
|
|
--------------------
|
|
-- Finish_Element --
|
|
--------------------
|
|
|
|
procedure Finish_Element (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
Info : constant Element_Descr := Ctx.Element;
|
|
begin
|
|
case Next.Typ is
|
|
when Context_Schema | Context_Redefine =>
|
|
Set (Handler.Shared.Global_Elements, Info.Name, Info);
|
|
when others =>
|
|
-- We might have added the type definition
|
|
Ctx.Elem_Details.Element := Ctx.Element;
|
|
end case;
|
|
end Finish_Element;
|
|
|
|
------------------------
|
|
-- Create_Simple_Type --
|
|
------------------------
|
|
|
|
procedure Create_Simple_Type
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
begin
|
|
Prepare_Type (Handler, Atts, Is_Simple => True);
|
|
|
|
if Ctx.Typ = Context_Simple_Restriction then
|
|
Ctx.Simple.Base :=
|
|
(Name => No_Qualified_Name,
|
|
Local => Handler.Contexts (Handler.Contexts_Last).Type_Info);
|
|
end if;
|
|
end Create_Simple_Type;
|
|
|
|
---------------------
|
|
-- Add_Type_Member --
|
|
---------------------
|
|
|
|
procedure Add_Type_Member
|
|
(Handler : access Schema_Reader'Class;
|
|
List : in out Type_Member_Array;
|
|
Member : Type_Member;
|
|
Loc : Location)
|
|
is
|
|
begin
|
|
for A in List'Range loop
|
|
if List (A) = No_Type_Member then
|
|
List (A) := Member;
|
|
return;
|
|
end if;
|
|
end loop;
|
|
|
|
Validation_Error
|
|
(Handler,
|
|
"Too many types in the union", Loc,
|
|
XML_Not_Implemented'Identity);
|
|
end Add_Type_Member;
|
|
|
|
------------------------
|
|
-- Finish_Simple_Type --
|
|
------------------------
|
|
|
|
procedure Finish_Simple_Type (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
begin
|
|
case Next.Typ is
|
|
when Context_Schema | Context_Redefine => null;
|
|
when Context_Element => Next.Element.Local_Type := Ctx.Type_Info;
|
|
when Context_Attribute =>
|
|
Next.Attribute.Attr.Local_Type := Ctx.Type_Info;
|
|
when Context_List =>
|
|
Add_Type_Member (Handler, Next.List.List_Items,
|
|
(Name => No_Qualified_Name,
|
|
Local => Ctx.Type_Info),
|
|
No_Location);
|
|
when Context_Union =>
|
|
Add_Type_Member (Handler, Next.Union.Union_Items,
|
|
(Name => No_Qualified_Name,
|
|
Local => Ctx.Type_Info),
|
|
No_Location);
|
|
when Context_Restriction =>
|
|
Next.Restriction.Restriction.Details :=
|
|
Handler.Shared.Types.Table (Ctx.Type_Info).Details;
|
|
when Context_Simple_Restriction =>
|
|
-- The simpleType is in fact the base type of the restriction. The
|
|
-- following was already done in Create_Simple_Type:
|
|
-- Next.Simple.Base.Local := Ctx.Type_Info;
|
|
null;
|
|
when others =>
|
|
Validation_Error
|
|
(Handler,
|
|
"Unsupported: ""simpleType"" in this context",
|
|
Except => XML_Not_Implemented'Identity);
|
|
end case;
|
|
end Finish_Simple_Type;
|
|
|
|
--------------------
|
|
-- Compute_Blocks --
|
|
--------------------
|
|
|
|
procedure Compute_Blocks
|
|
(Atts : Sax_Attribute_List;
|
|
Handler : access Schema_Reader'Class;
|
|
Blocks : out Block_Status;
|
|
Is_Set : out Boolean;
|
|
Index : Integer)
|
|
is
|
|
procedure On_Item (Str : Byte_Sequence);
|
|
procedure On_Item (Str : Byte_Sequence) is
|
|
begin
|
|
if Str = "restriction" then
|
|
Blocks (Block_Restriction) := True;
|
|
elsif Str = "extension" then
|
|
Blocks (Block_Extension) := True;
|
|
elsif Str = "substitution" then
|
|
Blocks (Block_Substitution) := True;
|
|
elsif Str = "#all" then
|
|
Blocks := (others => True);
|
|
else
|
|
Validation_Error
|
|
(Handler, "Invalid value for block: """ & Str & """");
|
|
end if;
|
|
end On_Item;
|
|
|
|
procedure For_Each is new For_Each_Item (On_Item);
|
|
begin
|
|
Is_Set := Index /= -1;
|
|
Blocks := No_Block;
|
|
|
|
if Index /= -1 then
|
|
For_Each (Get (Get_Value (Atts, Index)).all);
|
|
|
|
if Debug then
|
|
Output_Action ("Set_Block (" & To_String (Blocks) & ")");
|
|
end if;
|
|
end if;
|
|
end Compute_Blocks;
|
|
|
|
------------------
|
|
-- Compute_Form --
|
|
------------------
|
|
|
|
function Compute_Form
|
|
(Atts : Sax_Attribute_List;
|
|
Handler : access Schema_Reader'Class;
|
|
Index : Integer) return Form_Type is
|
|
begin
|
|
if Get_Value (Atts, Index) = Handler.Qualified then
|
|
return Qualified;
|
|
else
|
|
return Unqualified;
|
|
end if;
|
|
end Compute_Form;
|
|
|
|
-------------------
|
|
-- Compute_Final --
|
|
-------------------
|
|
|
|
function Compute_Final
|
|
(Atts : Sax_Attribute_List;
|
|
Handler : access Schema_Reader'Class;
|
|
Index : Integer) return Final_Status
|
|
is
|
|
Final : Final_Status;
|
|
|
|
procedure On_Item (Str : Byte_Sequence);
|
|
procedure On_Item (Str : Byte_Sequence) is
|
|
begin
|
|
if Str = "restriction" then
|
|
Final (Final_Restriction) := True;
|
|
elsif Str = "extension" then
|
|
Final (Final_Extension) := True;
|
|
elsif Str = "#all" then
|
|
Final := (others => True);
|
|
elsif Str = "union" then
|
|
Final (Final_Union) := True;
|
|
elsif Str = "list" then
|
|
Final (Final_List) := True;
|
|
else
|
|
Validation_Error
|
|
(Handler, "Invalid value for final: """ & Str & """");
|
|
end if;
|
|
end On_Item;
|
|
|
|
procedure For_Each is new For_Each_Item (On_Item);
|
|
begin
|
|
Final := (others => False);
|
|
|
|
if Index /= -1 then
|
|
For_Each (Get (Get_Value (Atts, Index)).all);
|
|
|
|
if Debug then
|
|
Output_Action ("Set_Final (" & To_String (Final) & ")");
|
|
end if;
|
|
end if;
|
|
|
|
return Final;
|
|
end Compute_Final;
|
|
|
|
------------------
|
|
-- Prepare_Type --
|
|
------------------
|
|
|
|
procedure Prepare_Type
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List;
|
|
Is_Simple : Boolean)
|
|
is
|
|
Info : Internal_Type_Descr (Is_Simple => Is_Simple);
|
|
Is_Set : Boolean;
|
|
Name : Qualified_Name;
|
|
Props : Type_Descr;
|
|
|
|
begin
|
|
Info.Loc := Handler.Current_Location;
|
|
Props.Block := Handler.Target_Block_Default;
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Mixed then
|
|
Props.Mixed := Get_Value_As_Boolean (Atts, J, False);
|
|
elsif Name.Local = Handler.Name then
|
|
Props.Name :=
|
|
(NS => Handler.Target_NS,
|
|
Local => Get_Value (Atts, J));
|
|
elsif Name.Local = Handler.Block then
|
|
Compute_Blocks (Atts, Handler, Props.Block, Is_Set, J);
|
|
elsif Name.Local = Handler.Final then
|
|
Props.Final := Compute_Final (Atts, Handler, J);
|
|
elsif Name.Local = Handler.S_Abstract then
|
|
Props.Is_Abstract := Get_Value_As_Boolean (Atts, J, False);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
-- block="substitution" does not apply to types, only to elements
|
|
Props.Block (Block_Substitution) := False;
|
|
|
|
Info.Properties := Props;
|
|
|
|
Append (Handler.Shared.Types, Info);
|
|
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Type_Def,
|
|
Type_Info => Last (Handler.Shared.Types)));
|
|
end Prepare_Type;
|
|
|
|
-------------------------
|
|
-- Create_Complex_Type --
|
|
-------------------------
|
|
|
|
procedure Create_Complex_Type
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List) is
|
|
begin
|
|
Prepare_Type (Handler, Atts, Is_Simple => False);
|
|
end Create_Complex_Type;
|
|
|
|
-------------------------
|
|
-- Finish_Complex_Type --
|
|
-------------------------
|
|
|
|
procedure Finish_Complex_Type (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
begin
|
|
case Next.Typ is
|
|
when Context_Element => Next.Element.Local_Type := Ctx.Type_Info;
|
|
when others => null;
|
|
end case;
|
|
end Finish_Complex_Type;
|
|
|
|
------------------------
|
|
-- Create_Restriction --
|
|
------------------------
|
|
|
|
procedure Create_Restriction
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Restr : Restriction_Descr;
|
|
Details : Type_Details_Access;
|
|
Name : Qualified_Name;
|
|
In_Type : constant Internal_Type_Index := Ctx.Type_Info;
|
|
begin
|
|
Restr.Loc := Handler.Current_Location;
|
|
Restr.Base := (NS => Handler.XML_Schema_URI,
|
|
Local => Handler.Any_Simple_Type);
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Base then
|
|
Restr.Base := Resolve_QName
|
|
(Handler, Get_Value (Atts, J), Handler.Target_NS,
|
|
Get_Location (Atts, J));
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
if Handler.Shared.Types.Table (In_Type).Is_Simple
|
|
or else Handler.Shared.Types.Table (In_Type).Simple.Kind /=
|
|
Simple_Type_None
|
|
then
|
|
if Restr.Base = (NS => Handler.XML_Schema_URI, Local => Handler.IDREF)
|
|
or else Restr.Base =
|
|
(NS => Handler.XML_Schema_URI, Local => Handler.IDREFS)
|
|
then
|
|
Validation_Error
|
|
(Handler,
|
|
"Unsupported type IDREF and IDREFS",
|
|
Except => XML_Not_Implemented'Identity);
|
|
end if;
|
|
|
|
if not Handler.Shared.Types.Table (In_Type).Is_Simple then
|
|
Details := new Type_Details'
|
|
(Kind => Type_Restriction,
|
|
Min_Occurs => (False, 1),
|
|
Max_Occurs => (False, 1),
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
Simple_Content_Restriction => True,
|
|
Restriction => Restr);
|
|
Insert_In_Type (Handler, Details);
|
|
end if;
|
|
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Simple_Restriction,
|
|
Simple => (Kind => Simple_Type_Restriction,
|
|
In_Process => False,
|
|
Facets => No_Facets,
|
|
Base =>
|
|
(Name => Restr.Base,
|
|
Local => No_Internal_Type_Index),
|
|
Loc => Handler.Current_Location)));
|
|
|
|
else
|
|
Details := new Type_Details'
|
|
(Kind => Type_Restriction,
|
|
Min_Occurs => (False, 1),
|
|
Max_Occurs => (False, 1),
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
Simple_Content_Restriction => False,
|
|
Restriction => Restr);
|
|
Insert_In_Type (Handler, Details);
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Restriction,
|
|
Restriction => Details));
|
|
end if;
|
|
end Create_Restriction;
|
|
|
|
------------------------
|
|
-- Finish_Restriction --
|
|
------------------------
|
|
|
|
procedure Finish_Restriction (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
begin
|
|
if Ctx.Typ = Context_Simple_Restriction then
|
|
pragma Assert (Next.Typ = Context_Type_Def);
|
|
Handler.Shared.Types.Table (Next.Type_Info).Simple := Ctx.Simple;
|
|
end if;
|
|
end Finish_Restriction;
|
|
|
|
------------------
|
|
-- Create_Union --
|
|
------------------
|
|
|
|
procedure Create_Union
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Name : Qualified_Name;
|
|
|
|
procedure Add_Union (Str : Byte_Sequence);
|
|
-- Add a unioned type to [Simple]
|
|
|
|
procedure Add_Union (Str : Byte_Sequence) is
|
|
Sym : constant Symbol := Find_Symbol (Handler.all, Str);
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Name : constant Qualified_Name :=
|
|
Resolve_QName (Handler, Sym, Handler.Target_NS,
|
|
Loc => Ctx.Union.Loc);
|
|
begin
|
|
Add_Type_Member
|
|
(Handler,
|
|
Ctx.Union.Union_Items,
|
|
(Name => Name, Local => No_Internal_Type_Index),
|
|
Ctx.Union.Loc);
|
|
end Add_Union;
|
|
|
|
procedure For_Each_Union is new For_Each_Item (Add_Union);
|
|
|
|
begin
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Union,
|
|
Union => (Kind => Simple_Type_Union,
|
|
In_Process => False,
|
|
Loc => Handler.Current_Location,
|
|
Union_Items => (others => No_Type_Member))));
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Member_Types then
|
|
For_Each_Union (Get (Get_Value (Atts, J)).all);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
end Create_Union;
|
|
|
|
------------------
|
|
-- Finish_Union --
|
|
------------------
|
|
|
|
procedure Finish_Union (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
begin
|
|
case Next.Typ is
|
|
when Context_Type_Def =>
|
|
Handler.Shared.Types.Table (Next.Type_Info).Simple := Ctx.Union;
|
|
when others =>
|
|
Validation_Error
|
|
(Handler,
|
|
"Unsupported: ""union"" in this context",
|
|
Except => XML_Not_Implemented'Identity);
|
|
end case;
|
|
end Finish_Union;
|
|
|
|
----------------------
|
|
-- Create_Extension --
|
|
----------------------
|
|
|
|
procedure Create_Extension
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Ext : Extension_Descr;
|
|
Name : Qualified_Name;
|
|
Details : Type_Details_Access;
|
|
In_Type : constant Internal_Type_Index := Ctx.Type_Info;
|
|
begin
|
|
Ext.Loc := Handler.Current_Location;
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Base then
|
|
Ext.Base := Resolve_QName
|
|
(Handler, Get_Value (Atts, J), Handler.Target_NS,
|
|
Loc => Get_Location (Atts, J));
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
if Ext.Base = No_Qualified_Name then
|
|
Validation_Error
|
|
(Handler, "Attribute ""base"" required for <extensionType>");
|
|
end if;
|
|
|
|
if Handler.Shared.Types.Table (In_Type).Is_Simple
|
|
or else Handler.Shared.Types.Table (In_Type).Simple.Kind /=
|
|
Simple_Type_None
|
|
then
|
|
if Debug then
|
|
Debug_Output ("Create extension: in simpleContent or simpleType");
|
|
end if;
|
|
|
|
if not Handler.Shared.Types.Table (In_Type).Is_Simple then
|
|
Details := new Type_Details'
|
|
(Kind => Type_Extension,
|
|
Min_Occurs => (False, 1),
|
|
Max_Occurs => (False, 1),
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
Simple_Content => True,
|
|
Extension => Ext);
|
|
Insert_In_Type (Handler, Details);
|
|
end if;
|
|
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Simple_Extension,
|
|
Simple => (Kind => Simple_Type_Extension,
|
|
In_Process => False,
|
|
Base => (Name => Ext.Base,
|
|
Local => No_Internal_Type_Index),
|
|
Facets => No_Facets,
|
|
Loc => Handler.Current_Location)));
|
|
else
|
|
Details := new Type_Details'
|
|
(Kind => Type_Extension,
|
|
Min_Occurs => (False, 1),
|
|
Max_Occurs => (False, 1),
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
Simple_Content => False,
|
|
Extension => Ext);
|
|
Insert_In_Type (Handler, Details);
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Extension,
|
|
Extension => Details));
|
|
end if;
|
|
end Create_Extension;
|
|
|
|
----------------------
|
|
-- Finish_Extension --
|
|
----------------------
|
|
|
|
procedure Finish_Extension (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
begin
|
|
if Ctx.Typ = Context_Simple_Extension then
|
|
pragma Assert (Next.Typ = Context_Type_Def); -- a simple type
|
|
Handler.Shared.Types.Table (Next.Type_Info).Simple := Ctx.Simple;
|
|
end if;
|
|
end Finish_Extension;
|
|
|
|
-----------------
|
|
-- Create_List --
|
|
-----------------
|
|
|
|
procedure Create_List
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Name : Qualified_Name;
|
|
begin
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_List,
|
|
List => (Kind => Simple_Type_List,
|
|
In_Process => False,
|
|
Loc => Handler.Current_Location,
|
|
List_Items => (others => No_Type_Member))));
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Item_Type then
|
|
Name := Resolve_QName
|
|
(Handler, Get_Value (Atts, J), Handler.Target_NS,
|
|
Loc => Get_Location (Atts, J));
|
|
Add_Type_Member
|
|
(Handler,
|
|
Handler.Contexts (Handler.Contexts_Last).List.List_Items,
|
|
(Name => Name, Local => No_Internal_Type_Index),
|
|
Handler.Current_Location);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
end Create_List;
|
|
|
|
-----------------
|
|
-- Finish_List --
|
|
-----------------
|
|
|
|
procedure Finish_List (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 1)'Access;
|
|
Next_Next : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last - 2)'Access;
|
|
begin
|
|
case Next.Typ is
|
|
when Context_Type_Def =>
|
|
if Next.Type_Info = No_Internal_Type_Index then
|
|
-- within a <simpleType><restriction><simpleType><list>
|
|
pragma Assert (Next_Next.Typ = Context_Simple_Restriction);
|
|
Next_Next.Simple := Ctx.List;
|
|
|
|
else
|
|
-- within a <simpleType><list>
|
|
pragma Assert (Next.Type_Info /= No_Internal_Type_Index);
|
|
|
|
Handler.Shared.Types.Table (Next.Type_Info).Simple := Ctx.List;
|
|
end if;
|
|
when others =>
|
|
Validation_Error
|
|
(Handler,
|
|
"Unsupported: ""list"" in this context",
|
|
Except => XML_Not_Implemented'Identity);
|
|
end case;
|
|
end Finish_List;
|
|
|
|
--------------------
|
|
-- Insert_In_Type --
|
|
--------------------
|
|
|
|
procedure Insert_In_Type
|
|
(Handler : access Schema_Reader'Class;
|
|
Element : in out Type_Details_Access)
|
|
is
|
|
procedure Append (List : in out Type_Details_Access;
|
|
Elem : Type_Details_Access);
|
|
procedure Append (List : in out Type_Details_Access;
|
|
Elem : Type_Details_Access)
|
|
is
|
|
Tmp : Type_Details_Access;
|
|
begin
|
|
if List = null then
|
|
List := Elem;
|
|
else
|
|
Tmp := List;
|
|
while Tmp.Next /= null loop
|
|
Tmp := Tmp.Next;
|
|
end loop;
|
|
|
|
Tmp.Next := Elem;
|
|
end if;
|
|
end Append;
|
|
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
|
|
begin
|
|
case Ctx.Typ is
|
|
when Context_Type_Def =>
|
|
if Handler.Shared.Types.Table (Ctx.Type_Info).Is_Simple then
|
|
Free (Element);
|
|
Validation_Error
|
|
(Handler, "Invalid element in simple type");
|
|
end if;
|
|
|
|
if Debug and then
|
|
Handler.Shared.Types.Table (Ctx.Type_Info).Details /= null
|
|
then
|
|
Debug_Output ("Insert_In_Type, type already has details "
|
|
& " when inserting " & Element.Kind'Img);
|
|
end if;
|
|
|
|
pragma Assert
|
|
(Handler.Shared.Types.Table (Ctx.Type_Info).Details = null);
|
|
|
|
Handler.Shared.Types.Table (Ctx.Type_Info).Details := Element;
|
|
|
|
when Context_Sequence =>
|
|
Append (Ctx.Seq.First_In_Seq, Element);
|
|
|
|
when Context_Choice =>
|
|
Append (Ctx.Choice.First_In_Choice, Element);
|
|
|
|
when Context_All =>
|
|
Append (Ctx.All_Detail.First_In_All, Element);
|
|
|
|
when Context_Group =>
|
|
if Ctx.Group.Details /= null then
|
|
Free (Element);
|
|
Validation_Error
|
|
(Handler, "Invalid element in non group");
|
|
end if;
|
|
|
|
Ctx.Group.Details := Element;
|
|
|
|
when Context_Extension =>
|
|
if Ctx.Extension.Extension.Details /= null then
|
|
Free (Element);
|
|
Validation_Error
|
|
(Handler, "Invalid element in non-empty extension");
|
|
end if;
|
|
|
|
Ctx.Extension.Extension.Details := Element;
|
|
|
|
when Context_Restriction =>
|
|
if Ctx.Restriction.Restriction.Details /= null then
|
|
Free (Element);
|
|
Validation_Error
|
|
(Handler, "Invalid element in non-empty restriction");
|
|
end if;
|
|
Ctx.Restriction.Restriction.Details := Element;
|
|
|
|
when Context_Simple_Restriction | Context_Simple_Extension =>
|
|
Free (Element);
|
|
|
|
when Context_Schema | Context_Attribute | Context_Element
|
|
| Context_Union
|
|
| Context_List | Context_Redefine | Context_Attribute_Group =>
|
|
|
|
Free (Element);
|
|
Validation_Error
|
|
(Handler,
|
|
"Unsupported: """ & Element.Kind'Img & """ in context "
|
|
& Ctx.Typ'Img,
|
|
Except => XML_Not_Implemented'Identity);
|
|
end case;
|
|
end Insert_In_Type;
|
|
|
|
-------------------
|
|
-- Create_Choice --
|
|
-------------------
|
|
|
|
procedure Create_Choice
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Min_Occurs, Max_Occurs : Occurrences := (False, 1);
|
|
Choice : Type_Details_Access;
|
|
begin
|
|
Get_Occurs (Handler, Atts, Min_Occurs, Max_Occurs);
|
|
Choice := new Type_Details'
|
|
(Kind => Type_Choice,
|
|
Min_Occurs => Min_Occurs,
|
|
Max_Occurs => Max_Occurs,
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
First_In_Choice => null);
|
|
Insert_In_Type (Handler, Choice);
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Choice,
|
|
Choice => Choice));
|
|
end Create_Choice;
|
|
|
|
---------------------
|
|
-- Create_Sequence --
|
|
---------------------
|
|
|
|
procedure Create_Sequence
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Min_Occurs, Max_Occurs : Occurrences := (False, 1);
|
|
Seq : Type_Details_Access;
|
|
begin
|
|
Get_Occurs (Handler, Atts, Min_Occurs, Max_Occurs);
|
|
Seq := new Type_Details'
|
|
(Kind => Type_Sequence,
|
|
Min_Occurs => Min_Occurs,
|
|
Max_Occurs => Max_Occurs,
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
First_In_Seq => null);
|
|
Insert_In_Type (Handler, Seq);
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Sequence,
|
|
Seq => Seq));
|
|
end Create_Sequence;
|
|
|
|
----------------------
|
|
-- Create_Attribute --
|
|
----------------------
|
|
|
|
procedure Create_Attribute
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Name : Qualified_Name;
|
|
Att : Attr_Descr (Kind => Kind_Attribute);
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
Has_Form : Boolean := False;
|
|
|
|
begin
|
|
Att.Attr.Descr.Form := Handler.Attribute_Form_Default;
|
|
Att.Loc := Handler.Current_Location;
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Name then
|
|
Att.Attr.Descr.Name := (NS => Handler.Target_NS,
|
|
Local => Get_Value (Atts, J));
|
|
elsif Name.Local = Handler.Typ then
|
|
Att.Attr.Typ := Resolve_QName
|
|
(Handler, Get_Value (Atts, J),
|
|
Loc => Get_Location (Atts, J));
|
|
|
|
if Att.Attr.Typ =
|
|
(NS => Handler.XML_Schema_URI, Local => Handler.IDREF)
|
|
or else Att.Attr.Typ =
|
|
(NS => Handler.XML_Schema_URI, Local => Handler.IDREFS)
|
|
then
|
|
Validation_Error
|
|
(Handler,
|
|
"Unsupported type IDREF and IDREFS",
|
|
Get_Location (Atts, J),
|
|
Except => XML_Not_Implemented'Identity);
|
|
end if;
|
|
|
|
elsif Name.Local = Handler.S_Use then
|
|
if Get_Value (Atts, J) = Handler.Required then
|
|
Att.Attr.Descr.Use_Type := Required;
|
|
elsif Get_Value (Atts, J) = Handler.Prohibited then
|
|
Att.Attr.Descr.Use_Type := Prohibited;
|
|
else
|
|
Att.Attr.Descr.Use_Type := Optional;
|
|
end if;
|
|
|
|
elsif Name.Local = Handler.Fixed then
|
|
Att.Attr.Descr.Fixed := Get_Value (Atts, J);
|
|
elsif Name.Local = Handler.Ref then
|
|
Att.Attr.Ref := Resolve_QName
|
|
(Handler, Get_Value (Atts, J), Handler.Target_NS,
|
|
Loc => Get_Location (Atts, J));
|
|
elsif Name.Local = Handler.Form then
|
|
Att.Attr.Descr.Form :=
|
|
Form_Type'Value (Get (Get_Value (Atts, J)).all);
|
|
Has_Form := True;
|
|
elsif Name.Local = Handler.Default then
|
|
Att.Attr.Descr.Default := Get_Value (Atts, J);
|
|
elsif Name.Local = Handler.Namespace_Target then
|
|
Att.Attr.Descr.Target_NS := Get_Value (Atts, J);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
-- See section 3.2.3 for valid attributes combination
|
|
|
|
if Att.Attr.Descr.Target_NS /= No_Symbol then
|
|
if Att.Attr.Descr.Name /= No_Qualified_Name then
|
|
Validation_Error
|
|
(Handler,
|
|
"name must be specified when targetNamespace is specified");
|
|
end if;
|
|
|
|
if Has_Form then
|
|
Validation_Error
|
|
(Handler,
|
|
"Cannot specify ""form"" when targetNamespace is given");
|
|
end if;
|
|
|
|
Validation_Error
|
|
(Handler,
|
|
"targetNamespace not supported in attribute declaration",
|
|
Except => XML_Not_Implemented'Identity);
|
|
end if;
|
|
|
|
if Has_Form and then Att.Attr.Ref /= No_Qualified_Name then
|
|
Validation_Error
|
|
(Handler,
|
|
"Attributes ""form"" and ""ref"" cannot be both specified");
|
|
end if;
|
|
|
|
if Att.Attr.Typ /= No_Qualified_Name then
|
|
if Att.Attr.Ref /= No_Qualified_Name then
|
|
Validation_Error
|
|
(Handler,
|
|
"Attributes ""type"" and ""ref"" cannot be both specified");
|
|
end if;
|
|
end if;
|
|
|
|
if Att.Attr.Descr.Fixed /= No_Symbol
|
|
and then Att.Attr.Descr.Default /= No_Symbol
|
|
then
|
|
Validation_Error
|
|
(Handler,
|
|
"Attributes ""fixed"" and ""default"" cannot be both specified");
|
|
end if;
|
|
|
|
if Att.Attr.Descr.Default /= No_Symbol
|
|
and then Att.Attr.Descr.Use_Type /= Optional
|
|
then
|
|
Validation_Error
|
|
(Handler,
|
|
"Use must be ""optional"" when a default value is specified");
|
|
end if;
|
|
|
|
if Get_XSD_Version (Handler.Grammar) = XSD_1_1
|
|
and then Att.Attr.Descr.Fixed /= No_Symbol
|
|
and then Att.Attr.Descr.Use_Type = Prohibited
|
|
then
|
|
Validation_Error
|
|
(Handler,
|
|
"""prohibited"" is forbidden when"
|
|
& " a fixed value is specified");
|
|
end if;
|
|
|
|
if Att.Attr.Descr.Name /= No_Qualified_Name then
|
|
case Ctx.Typ is
|
|
when Context_Attribute_Group | Context_Type_Def =>
|
|
null;
|
|
|
|
when others =>
|
|
if Handler.Target_NS = Handler.XML_Instance_URI then
|
|
Validation_Error
|
|
(Handler,
|
|
"Invalid target namespace for attribute declaration: """
|
|
& Get (Handler.Target_NS).all & """");
|
|
end if;
|
|
end case;
|
|
end if;
|
|
|
|
Att.Attr.Descr.Is_Local := Att.Attr.Ref = No_Qualified_Name;
|
|
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_Attribute,
|
|
Attribute => Att));
|
|
end Create_Attribute;
|
|
|
|
----------------------
|
|
-- Insert_Attribute --
|
|
----------------------
|
|
|
|
procedure Insert_Attribute
|
|
(Handler : access Schema_Reader'Class;
|
|
In_Context : Natural;
|
|
Attribute : Attr_Descr)
|
|
is
|
|
Ctx : Context renames Handler.Contexts (In_Context);
|
|
Index : Natural;
|
|
Ctx2 : Context_Access;
|
|
begin
|
|
case Ctx.Typ is
|
|
when Context_Type_Def =>
|
|
Append
|
|
(Handler.Shared.Types.Table (Ctx.Type_Info).Attributes,
|
|
Attribute);
|
|
|
|
when Context_Schema | Context_Redefine =>
|
|
Set
|
|
(Handler.Shared.Global_Attributes,
|
|
Attribute.Attr.Descr.Name, Attribute.Attr);
|
|
|
|
when Context_Extension | Context_Restriction =>
|
|
Index := Handler.Contexts_Last;
|
|
while Index >= Handler.Contexts'First loop
|
|
Ctx2 := Handler.Contexts (Index)'Access;
|
|
if Ctx2.Typ = Context_Type_Def then
|
|
Append
|
|
(Handler.Shared.Types.Table (Ctx2.Type_Info).Attributes,
|
|
Attribute);
|
|
exit;
|
|
end if;
|
|
|
|
Index := Index - 1;
|
|
end loop;
|
|
|
|
when Context_Simple_Extension | Context_Simple_Restriction =>
|
|
pragma Assert
|
|
(Handler.Contexts (In_Context - 1).Typ = Context_Type_Def);
|
|
pragma Assert -- a <simpleType><extension> cannot have attributes
|
|
(not Handler.Shared.Types.Table
|
|
(Handler.Contexts (In_Context - 1).Type_Info).Is_Simple);
|
|
|
|
Append
|
|
(Handler.Shared.Types.Table
|
|
(Handler.Contexts (In_Context - 1).Type_Info).Attributes,
|
|
Attribute);
|
|
|
|
when Context_Attribute_Group =>
|
|
Append (Ctx.Attr_Group.Attributes, Attribute);
|
|
|
|
when Context_Element | Context_Sequence | Context_Choice
|
|
| Context_Attribute | Context_All
|
|
| Context_Union | Context_List | Context_Group =>
|
|
Validation_Error
|
|
(Handler,
|
|
"Unsupported: ""attribute"" in this context",
|
|
Except => XML_Not_Implemented'Identity);
|
|
end case;
|
|
end Insert_Attribute;
|
|
|
|
----------------------
|
|
-- Finish_Attribute --
|
|
----------------------
|
|
|
|
procedure Finish_Attribute (Handler : access Schema_Reader'Class) is
|
|
Ctx : constant Context_Access :=
|
|
Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
begin
|
|
Insert_Attribute (Handler, Handler.Contexts_Last - 1, Ctx.Attribute);
|
|
end Finish_Attribute;
|
|
|
|
-------------------
|
|
-- Create_Schema --
|
|
-------------------
|
|
|
|
procedure Create_Schema
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Info : Schema_Descr;
|
|
Is_Set : Boolean := False;
|
|
Name : Qualified_Name;
|
|
begin
|
|
Info.Element_Form_Default := Unqualified;
|
|
Info.Attribute_Form_Default := Unqualified;
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.S_Element_Form_Default then
|
|
Info.Element_Form_Default := Compute_Form (Atts, Handler, J);
|
|
elsif Name.Local = Handler.S_Attribute_Form_Default then
|
|
Info.Attribute_Form_Default := Compute_Form (Atts, Handler, J);
|
|
elsif Name.Local = Handler.Block_Default then
|
|
Compute_Blocks (Atts, Handler, Info.Block, Is_Set, J);
|
|
elsif Name.Local = Handler.Namespace_Target then
|
|
Info.Target_NS := Get_Value (Atts, J);
|
|
end if;
|
|
|
|
elsif Name.NS = Handler.XML_Instance_URI then
|
|
if Name.Local = Handler.No_Namespace_Schema_Location then
|
|
-- Already handled through Hook_Start_Element when validating
|
|
-- the grammar itself, but needed if we do not validate the
|
|
-- grammar
|
|
Parse_Grammar
|
|
(Handler,
|
|
URI => Empty_String,
|
|
Xsd_File => Get_Value (Atts, J),
|
|
Do_Create_NFA => False);
|
|
|
|
elsif Name.Local = Handler.Schema_Location then
|
|
-- Already handled through Hook_Start_Element when validating
|
|
-- the grammar itself
|
|
Parse_Grammars
|
|
(Handler, Get_Value (Atts, J), Do_Create_NFA => False);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
if Info.Target_NS /= No_Symbol then
|
|
if Debug then
|
|
Output_Action ("Get_NS (Handler.Created_Grammar, """
|
|
& Get (Info.Target_NS).all & """, Handler.Target_NS)");
|
|
end if;
|
|
|
|
Handler.Target_NS := Info.Target_NS;
|
|
end if;
|
|
|
|
Handler.Element_Form_Default := Info.Element_Form_Default;
|
|
Handler.Attribute_Form_Default := Info.Attribute_Form_Default;
|
|
|
|
if Is_Set then
|
|
Handler.Target_Block_Default := Info.Block;
|
|
end if;
|
|
|
|
Push_Context (Handler, (Typ => Context_Schema));
|
|
end Create_Schema;
|
|
|
|
--------------------------------
|
|
-- Process_Contents_From_Atts --
|
|
--------------------------------
|
|
|
|
function Process_Contents_From_Atts
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List;
|
|
Index : Integer) return Process_Contents_Type is
|
|
begin
|
|
if Get_Value (Atts, Index) = Handler.Lax then
|
|
return Process_Lax;
|
|
elsif Get_Value (Atts, Index) = Handler.Strict then
|
|
return Process_Strict;
|
|
else
|
|
return Process_Skip;
|
|
end if;
|
|
end Process_Contents_From_Atts;
|
|
|
|
----------------
|
|
-- Create_Any --
|
|
----------------
|
|
|
|
procedure Create_Any
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Details : Type_Details_Access;
|
|
Any : Internal_Any_Descr;
|
|
Name : Qualified_Name;
|
|
Min_Occurs, Max_Occurs : Occurrences := (False, 1);
|
|
|
|
begin
|
|
Any.Target_NS := Handler.Target_NS;
|
|
Any.Namespaces := Handler.Any_Namespace;
|
|
|
|
for J in 1 .. Get_Length (Atts) loop
|
|
Name := Get_Name (Atts, J);
|
|
if Name.NS = Empty_String then
|
|
if Name.Local = Handler.Namespace then
|
|
Any.Namespaces := Get_Value (Atts, J);
|
|
elsif Name.Local = Handler.Process_Contents then
|
|
Any.Process_Contents :=
|
|
Process_Contents_From_Atts (Handler, Atts, J);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
Get_Occurs (Handler, Atts, Min_Occurs, Max_Occurs);
|
|
Details := new Type_Details'
|
|
(Kind => Type_Any,
|
|
Min_Occurs => Min_Occurs,
|
|
Max_Occurs => Max_Occurs,
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
Any => Any);
|
|
Insert_In_Type (Handler, Details);
|
|
end Create_Any;
|
|
|
|
----------------
|
|
-- Create_All --
|
|
----------------
|
|
|
|
procedure Create_All
|
|
(Handler : access Schema_Reader'Class;
|
|
Atts : Sax_Attribute_List)
|
|
is
|
|
Min_Occurs, Max_Occurs : Occurrences := (False, 1);
|
|
Details : Type_Details_Access;
|
|
begin
|
|
Get_Occurs (Handler, Atts, Min_Occurs, Max_Occurs);
|
|
Details := new Type_Details'
|
|
(Kind => Type_All,
|
|
Min_Occurs => Min_Occurs,
|
|
Max_Occurs => Max_Occurs,
|
|
Loc => Handler.Current_Location,
|
|
In_Process => False,
|
|
Next => null,
|
|
First_In_All => null);
|
|
Insert_In_Type (Handler, Details);
|
|
Push_Context
|
|
(Handler,
|
|
(Typ => Context_All,
|
|
All_Detail => Details));
|
|
end Create_All;
|
|
|
|
-------------------
|
|
-- Start_Element --
|
|
-------------------
|
|
|
|
overriding procedure Start_Element
|
|
(Handler : in out Schema_Reader;
|
|
NS : Sax.Utils.XML_NS;
|
|
Local_Name : Sax.Symbols.Symbol;
|
|
Atts : Sax.Readers.Sax_Attribute_List)
|
|
is
|
|
H : constant Schema_Reader_Access := Handler'Unchecked_Access;
|
|
Ctx : Context_Access;
|
|
begin
|
|
if Debug then
|
|
Output_Seen ("Start " & Get (Local_Name).all
|
|
& " at " & To_String (Handler.Current_Location));
|
|
end if;
|
|
|
|
-- Check the grammar
|
|
Start_Element (Validating_Reader (Handler), NS, Local_Name, Atts);
|
|
|
|
-- Process the element
|
|
|
|
if Handler.Contexts = null then
|
|
if Local_Name /= Handler.S_Schema then
|
|
Validation_Error (H, "Root element must be <schema>");
|
|
end if;
|
|
|
|
Create_Schema (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Annotation then
|
|
Handler.In_Annotation := True;
|
|
|
|
elsif Local_Name = Handler.Notation then
|
|
Create_Notation (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Element then
|
|
Create_Element (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Complex_Type then
|
|
Create_Complex_Type (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Simple_Type then
|
|
Create_Simple_Type (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Restriction then
|
|
Create_Restriction (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Extension then
|
|
Create_Extension (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Any_Attribute then
|
|
Create_Any_Attribute (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Pattern then
|
|
Ctx := Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
pragma Assert (Ctx.Typ = Context_Simple_Restriction);
|
|
pragma Assert (Ctx.Simple.Kind = Simple_Type_Restriction);
|
|
-- Use the non-normalized value for <pattern>
|
|
Add_Facet
|
|
(Grammar => Handler.Grammar,
|
|
Facets => Ctx.Simple.Facets,
|
|
Facet_Name => Local_Name,
|
|
Value => Get_Non_Normalized_Value
|
|
(Atts, Get_Index (Atts, Empty_String, Handler.Value)),
|
|
Loc => Handler.Current_Location);
|
|
|
|
elsif Local_Name = Handler.Maxlength
|
|
or else Local_Name = Handler.Minlength
|
|
or else Local_Name = Handler.Length
|
|
or else Local_Name = Handler.Enumeration
|
|
or else Local_Name = Handler.Whitespace
|
|
or else Local_Name = Handler.Total_Digits
|
|
or else Local_Name = Handler.Fraction_Digits
|
|
or else Local_Name = Handler.MaxInclusive
|
|
or else Local_Name = Handler.MaxExclusive
|
|
or else Local_Name = Handler.MinInclusive
|
|
or else Local_Name = Handler.MinExclusive
|
|
then
|
|
Ctx := Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
pragma Assert (Ctx.Typ = Context_Simple_Restriction);
|
|
pragma Assert (Ctx.Simple.Kind = Simple_Type_Restriction);
|
|
Add_Facet
|
|
(Grammar => Handler.Grammar,
|
|
Facets => Ctx.Simple.Facets,
|
|
Facet_Name => Local_Name,
|
|
Value => Get_Value
|
|
(Atts, Get_Index (Atts, Empty_String, Handler.Value)),
|
|
Loc => Handler.Current_Location);
|
|
|
|
elsif Local_Name = Handler.S_All then
|
|
Create_All (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Sequence then
|
|
Create_Sequence (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Choice then
|
|
Create_Choice (H, Atts);
|
|
|
|
elsif Local_Name = Handler.List then
|
|
Create_List (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Union then
|
|
Create_Union (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Attribute then
|
|
Create_Attribute (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Group then
|
|
Create_Group (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Simple_Content then
|
|
Ctx := Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
pragma Assert (Ctx.Typ = Context_Type_Def);
|
|
Handler.Shared.Types.Table (Ctx.Type_Info).Simple :=
|
|
(Kind => Simple_Type,
|
|
In_Process => False,
|
|
Loc => Handler.Current_Location);
|
|
Handler.Shared.Types.Table (Ctx.Type_Info).Properties.Mixed := True;
|
|
|
|
elsif Local_Name = Handler.Complex_Content then
|
|
Ctx := Handler.Contexts (Handler.Contexts_Last)'Access;
|
|
pragma Assert (Ctx.Typ = Context_Type_Def);
|
|
|
|
-- Do not reset Properties.Mixed here, since it might have been set
|
|
-- to "true" on the parent <complexType> node.
|
|
|
|
elsif Local_Name = Handler.Attribute_Group then
|
|
Create_Attribute_Group (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Any then
|
|
Create_Any (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Redefine then
|
|
Validation_Error
|
|
(Handler'Access,
|
|
"Unsupported <redefined>",
|
|
Except => XML_Not_Implemented'Identity);
|
|
Create_Redefine (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Include then
|
|
Create_Include (H, Atts);
|
|
|
|
elsif Local_Name = Handler.Import then
|
|
Create_Import (H, Atts);
|
|
|
|
elsif Handler.In_Annotation then
|
|
null; -- ignore all tags
|
|
|
|
elsif Handler.Feature_Ignore_Unsupported_XSD_Elements
|
|
and then
|
|
(Local_Name = Handler.Keyref
|
|
or else Local_Name = Handler.Key
|
|
or else Local_Name = Handler.Selector
|
|
or else Local_Name = Handler.Unique
|
|
or else Local_Name = Handler.Field)
|
|
then
|
|
Warning
|
|
(Handler,
|
|
Create (Message => "Unsupported element in the schema: "
|
|
& Get (Local_Name).all,
|
|
Loc => Handler.Current_Location));
|
|
|
|
else
|
|
Validation_Error
|
|
(Handler'Access,
|
|
"Unsupported element in the schema: " & Get (Local_Name).all,
|
|
Except => XML_Not_Implemented'Identity);
|
|
end if;
|
|
end Start_Element;
|
|
|
|
-----------------
|
|
-- End_Element --
|
|
-----------------
|
|
|
|
overriding procedure End_Element
|
|
(Handler : in out Schema_Reader;
|
|
NS : Sax.Utils.XML_NS;
|
|
Local_Name : Sax.Symbols.Symbol)
|
|
is
|
|
H : constant Schema_Reader_Access := Handler'Unchecked_Access;
|
|
Handled : Boolean := True;
|
|
begin
|
|
-- Check the grammar
|
|
End_Element (Validating_Reader (Handler), NS, Local_Name);
|
|
|
|
-- Process the tag
|
|
if Local_Name = Handler.Element then
|
|
Finish_Element (H);
|
|
|
|
elsif Local_Name = Handler.S_Schema then
|
|
null;
|
|
|
|
elsif Local_Name = Handler.Complex_Type then
|
|
Finish_Complex_Type (H);
|
|
|
|
elsif Local_Name = Handler.Simple_Type then
|
|
Finish_Simple_Type (H);
|
|
|
|
elsif Local_Name = Handler.S_All then
|
|
null;
|
|
|
|
elsif Local_Name = Handler.Sequence then
|
|
null;
|
|
|
|
elsif Local_Name = Handler.Any_Attribute then
|
|
Handled := False;
|
|
|
|
elsif Local_Name = Handler.Choice then
|
|
null;
|
|
|
|
elsif Local_Name = Handler.Restriction then
|
|
Finish_Restriction (H);
|
|
|
|
elsif Local_Name = Handler.Extension then
|
|
Finish_Extension (H);
|
|
|
|
elsif Local_Name = Handler.Attribute then
|
|
Finish_Attribute (H);
|
|
|
|
elsif Local_Name = Handler.Union then
|
|
Finish_Union (H);
|
|
|
|
elsif Local_Name = Handler.List then
|
|
Finish_List (H);
|
|
|
|
elsif Local_Name = Handler.Maxlength
|
|
or else Local_Name = Handler.Pattern
|
|
or else Local_Name = Handler.Minlength
|
|
or else Local_Name = Handler.Enumeration
|
|
or else Local_Name = Handler.Whitespace
|
|
or else Local_Name = Handler.Total_Digits
|
|
or else Local_Name = Handler.Fraction_Digits
|
|
or else Local_Name = Handler.MaxInclusive
|
|
or else Local_Name = Handler.MaxExclusive
|
|
or else Local_Name = Handler.MinInclusive
|
|
or else Local_Name = Handler.MinExclusive
|
|
then
|
|
Handled := False;
|
|
|
|
elsif Local_Name = Handler.Attribute_Group then
|
|
Finish_Attribute_Group (H);
|
|
|
|
elsif Local_Name = Handler.Redefine then
|
|
null;
|
|
|
|
elsif Local_Name = Handler.Group then
|
|
Finish_Group (H);
|
|
|
|
elsif Local_Name = Handler.Any
|
|
or else Local_Name = Handler.Include
|
|
or else Local_Name = Handler.Import
|
|
or else Local_Name = Handler.Simple_Content
|
|
or else Local_Name = Handler.Complex_Content
|
|
then
|
|
Handled := False;
|
|
|
|
elsif Local_Name = Handler.Annotation then
|
|
Handler.In_Annotation := False;
|
|
Handled := False;
|
|
|
|
else
|
|
if Debug then
|
|
Output_Action
|
|
("Close tag not handled yet: " & Get (Local_Name).all);
|
|
end if;
|
|
Handled := False;
|
|
end if;
|
|
|
|
-- Release the context
|
|
if Handled then
|
|
Handler.Contexts_Last := Handler.Contexts_Last - 1;
|
|
end if;
|
|
end End_Element;
|
|
|
|
----------------
|
|
-- Characters --
|
|
----------------
|
|
|
|
procedure Characters
|
|
(Handler : in out Schema_Reader; Ch : Unicode.CES.Byte_Sequence)
|
|
is
|
|
begin
|
|
Characters (Validating_Reader (Handler), Ch);
|
|
end Characters;
|
|
|
|
----------
|
|
-- Free --
|
|
----------
|
|
|
|
procedure Free (Self : in out Type_Details_Access) is
|
|
procedure Unchecked_Free is new Ada.Unchecked_Deallocation
|
|
(Type_Details, Type_Details_Access);
|
|
Next : Type_Details_Access;
|
|
begin
|
|
while Self /= null loop
|
|
Next := Self.Next;
|
|
|
|
case Self.Kind is
|
|
when Type_Empty | Type_Element | Type_Any => null;
|
|
when Type_Sequence => Free (Self.First_In_Seq);
|
|
when Type_Choice => Free (Self.First_In_Choice);
|
|
when Type_All => Free (Self.First_In_All);
|
|
when Type_Group => Free (Self.Group.Details);
|
|
when Type_Extension =>
|
|
Free (Self.Extension.Details);
|
|
when Type_Restriction =>
|
|
Free (Self.Restriction.Details);
|
|
end case;
|
|
|
|
Unchecked_Free (Self);
|
|
Self := Next;
|
|
end loop;
|
|
end Free;
|
|
|
|
-----------------
|
|
-- Set_Feature --
|
|
-----------------
|
|
|
|
overriding procedure Set_Feature
|
|
(Parser : in out Schema_Reader; Name : String; Value : Boolean) is
|
|
begin
|
|
if Name = Feature_Ignore_Unsupported_XSD_Elements then
|
|
Parser.Feature_Ignore_Unsupported_XSD_Elements := Value;
|
|
else
|
|
Set_Feature (Validating_Reader (Parser), Name, Value);
|
|
end if;
|
|
end Set_Feature;
|
|
|
|
-----------------
|
|
-- Get_Feature --
|
|
-----------------
|
|
|
|
overriding function Get_Feature
|
|
(Parser : Schema_Reader; Name : String) return Boolean is
|
|
begin
|
|
if Name = Feature_Ignore_Unsupported_XSD_Elements then
|
|
return Parser.Feature_Ignore_Unsupported_XSD_Elements;
|
|
else
|
|
return Get_Feature (Validating_Reader (Parser), Name);
|
|
end if;
|
|
end Get_Feature;
|
|
|
|
end Schema.Schema_Readers;
|