blob: f90e6f1fd61083cfaaafeb76816969b8d13c91eb [file] [log] [blame]
/**************************************************************
*
* 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<Schema> 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<Schema> aTopLevelSchemas)
{
maLog.AddComment("top level elements");
maLog.StartBlock();
final String sTypeName = "<top-level>";
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<Element> CollectElements (final ComplexType aType)
{
final Vector<Element> 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<Any> CollectAnys (final ComplexType aType)
{
final Vector<Any> aAnys = new Vector<>();
for (final INode aNode : new DereferencingNodeIterator(aType, maSchemaBase, false))
{
if (aNode.GetNodeType() == NodeType.Any)
aAnys.add((Any)aNode);
}
return aAnys;
}
}