/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ package org.apache.openoffice.ooxml.schema.automaton; import java.io.File; import java.util.Vector; import org.apache.openoffice.ooxml.schema.iterator.DereferencingNodeIterator; import org.apache.openoffice.ooxml.schema.model.base.INode; import org.apache.openoffice.ooxml.schema.model.base.NodeType; import org.apache.openoffice.ooxml.schema.model.complex.Any; import org.apache.openoffice.ooxml.schema.model.complex.ComplexType; import org.apache.openoffice.ooxml.schema.model.complex.Element; import org.apache.openoffice.ooxml.schema.model.schema.Schema; import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase; /** Create a set of stack automatons for a given set of schemas. * Creates one automaton for each complex type and one for the top level elements. * * Input files but are not validated to conform to the schemas. */ public class NonValidatingCreator extends CreatorBase { public NonValidatingCreator ( final SchemaBase aSchemaBase, final File aLogFile) { super(aSchemaBase, aLogFile); } public FiniteAutomatonContainer Create ( final Iterable aTopLevelSchemas) { final FiniteAutomatonContainer aAutomatons = new FiniteAutomatonContainer(maStateContainer); // Create a single automaton for all top level elements. aAutomatons.AddAutomaton( null, CreateForTopLevelElements(aTopLevelSchemas)); // Create one automaton for each complex type. for (final ComplexType aComplexType : maSchemaBase.ComplexTypes.GetSorted()) aAutomatons.AddAutomaton( aComplexType.GetName(), CreateForComplexType(aComplexType)); // Create one automaton for each simple type that is referenced by an element. for (final INode aSimpleType : maElementSimpleTypes) aAutomatons.AddAutomaton( aSimpleType.GetName(), CreateForSimpleType(aSimpleType)); maLog.Close(); return aAutomatons; } private FiniteAutomaton CreateForTopLevelElements ( final Iterable aTopLevelSchemas) { maLog.AddComment("top level elements"); maLog.StartBlock(); final String sTypeName = ""; final StateContext aStateContext = new StateContext( maStateContainer, sTypeName); final State aStartState = aStateContext.GetStartState(); final State aEndState = aStateContext.CreateEndState(); // top level elements for (final Schema aSchema : aTopLevelSchemas) { maLog.AddComment("schema %s", aSchema.GetShortName()); maLog.StartBlock(); for (final Element aElement : aSchema.TopLevelElements.GetSorted()) { maLog.AddComment("Element: on '%s' go from %s to %s via %s", aElement.GetElementName().GetDisplayName(), aStartState.GetFullname(), aEndState.GetFullname(), aElement.GetTypeName().GetStateName()); aStateContext.GetStartState().AddTransition( new Transition( aStartState, aEndState, aElement.GetElementName(), aElement.GetTypeName().GetStateName())); } maLog.EndBlock(); } maLog.EndBlock(); return new FiniteAutomaton(aStateContext, null, null); } private FiniteAutomaton CreateForComplexType (final ComplexType aComplexType) { maLog.printf("\n"); maLog.AddComment ("Complex Type %s defined in %s.", aComplexType.GetName().GetDisplayName(), aComplexType.GetLocation()); maLog.StartBlock(); final StateContext aStateContext = new StateContext( maStateContainer, aComplexType.GetName().GetStateName()); for (final Element aElement : CollectElements(aComplexType)) { maLog.AddComment("Element: on '%s' go from %s to %s via %s", aElement.GetElementName().GetDisplayName(), aStateContext.GetStartState().GetFullname(), aStateContext.GetStartState().GetFullname(), aElement.GetTypeName().GetStateName()); aStateContext.GetStartState().AddTransition( new Transition( aStateContext.GetStartState(), aStateContext.GetStartState(), aElement.GetElementName(), aElement.GetTypeName().GetStateName())); // For elements whose type is a simple type we have to remember that // simple type for later (and then create an NFA for it.) final INode aSimpleType = maSchemaBase.GetSimpleTypeForName( aElement.GetTypeName()); if (aSimpleType != null) maElementSimpleTypes.add(aSimpleType); } for (final Any aAny : CollectAnys(aComplexType)) { AddSkipTransition( aStateContext.GetStartState(), new SkipData( aAny.GetProcessContentsFlag(), aAny.GetNamespaces())); } // Collect all attributes. maAttributes = new Vector<>(); for (final INode aNode : new DereferencingNodeIterator(aComplexType, maSchemaBase, true)) ProcessAttributes(aNode); aStateContext.GetStartState().SetIsAccepting(); maLog.EndBlock(); return new FiniteAutomaton(aStateContext, maAttributes, aComplexType.GetLocation()); } /** Collect all elements inside the type tree that is rooted in the given * complex type. */ private Vector CollectElements (final ComplexType aType) { final Vector aElements = new Vector<>(); for (final INode aNode : new DereferencingNodeIterator(aType, maSchemaBase, false)) { if (aNode.GetNodeType() == NodeType.Element) aElements.add((Element)aNode); } return aElements; } private Vector CollectAnys (final ComplexType aType) { final Vector aAnys = new Vector<>(); for (final INode aNode : new DereferencingNodeIterator(aType, maSchemaBase, false)) { if (aNode.GetNodeType() == NodeType.Any) aAnys.add((Any)aNode); } return aAnys; } }