summaryrefslogtreecommitdiff
path: root/ooxml/source/framework/SchemaParser
diff options
context:
space:
mode:
Diffstat (limited to 'ooxml/source/framework/SchemaParser')
-rw-r--r--ooxml/source/framework/SchemaParser/.classpath6
-rw-r--r--ooxml/source/framework/SchemaParser/.project17
-rw-r--r--ooxml/source/framework/SchemaParser/.settings/org.eclipse.jdt.core.prefs11
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/SchemaReader.java510
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/Test.java81
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/CreatorBase.java124
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/DFACreator.java280
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/EpsilonTransition.java70
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomaton.java169
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomatonContainer.java166
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/HopcroftMinimizer.java380
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/NonValidatingCreator.java212
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/SkipData.java54
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/State.java263
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContainer.java73
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContext.java269
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateSet.java245
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/Transition.java97
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/ValidatingCreator.java793
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/LogGenerator.java313
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/ParserTablesGenerator.java555
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/HtmlGenerator.java623
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/code.js442
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/display.css57
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/linking-template.html22
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/template.html24
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeIterator.java109
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeNodeIterator.java112
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/DereferencingNodeIterator.java111
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/NodeIterator.java68
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/PermutationIterator.java137
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/misc/Log.java126
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/Attribute.java91
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeBase.java117
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroup.java65
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroupReference.java110
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeReference.java115
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INode.java39
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeReference.java32
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeVisitor.java85
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Location.java69
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Node.java172
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeType.java53
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeVisitorAdapter.java203
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/QualifiedName.java149
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/All.java96
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Any.java112
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Choice.java68
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexContent.java65
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexType.java72
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexTypeReference.java100
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Element.java109
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ElementReference.java106
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Extension.java160
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Group.java70
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/GroupReference.java109
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/OccurrenceIndicator.java152
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Sequence.java73
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/CopyVisitor.java112
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/RequestVisitor.java128
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/SchemaOptimizer.java140
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/NamespaceMap.java178
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/Schema.java107
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/SchemaBase.java121
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/TypeContainer.java100
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltIn.java103
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltInType.java109
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/List.java84
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Restriction.java337
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleContent.java65
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleType.java102
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleTypeReference.java107
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Union.java68
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/FormDefault.java31
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/SchemaParser.java1211
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XmlNamespace.java69
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XsdNamespace.java29
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/BlobNode.java131
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/DateTimeNode.java92
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/EnumerationNode.java27
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNode.java48
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNodeVisitor.java31
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/NumberNode.java310
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeContainer.java102
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptor.java86
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptorFactory.java307
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeNodeVisitorAdapter.java60
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/StringNode.java269
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/UnionNode.java151
89 files changed, 13926 insertions, 0 deletions
diff --git a/ooxml/source/framework/SchemaParser/.classpath b/ooxml/source/framework/SchemaParser/.classpath
new file mode 100644
index 000000000000..fb565a588d8a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ooxml/source/framework/SchemaParser/.project b/ooxml/source/framework/SchemaParser/.project
new file mode 100644
index 000000000000..05958e177e81
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>SchemaParser</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/ooxml/source/framework/SchemaParser/.settings/org.eclipse.jdt.core.prefs b/ooxml/source/framework/SchemaParser/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000000..7341ab1683c4
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/SchemaReader.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/SchemaReader.java
new file mode 100644
index 000000000000..bf15b39d71e2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/SchemaReader.java
@@ -0,0 +1,510 @@
+/**************************************************************
+*
+* 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;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.openoffice.ooxml.schema.automaton.FiniteAutomatonContainer;
+import org.apache.openoffice.ooxml.schema.automaton.NonValidatingCreator;
+import org.apache.openoffice.ooxml.schema.automaton.ValidatingCreator;
+import org.apache.openoffice.ooxml.schema.generator.LogGenerator;
+import org.apache.openoffice.ooxml.schema.generator.ParserTablesGenerator;
+import org.apache.openoffice.ooxml.schema.generator.html.HtmlGenerator;
+import org.apache.openoffice.ooxml.schema.model.schema.Schema;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.parser.SchemaParser;
+import org.apache.openoffice.ooxml.schema.simple.SimpleTypeContainer;
+
+public class SchemaReader
+{
+ public static void main (final String ... aArgumentList)
+ {
+ if (aArgumentList.length != 1)
+ {
+ System.err.printf("usage: SchemaParser <driver-file>\n");
+ System.err.printf(" driver file can contain these lines:\n");
+ System.err.printf("# Comments\n");
+ System.err.printf(" are ignored\n");
+ System.err.printf("schema <mark> <file-name>\n");
+ System.err.printf(" specifies a top-level schema file to read\n");
+ System.err.printf("output-schema <file-name>\n");
+ System.err.printf(" write schema information to file\n");
+ System.err.printf("output-optimized-schema <file-name>\n");
+ System.err.printf(" write information about optimized schema to file\n");
+ System.exit(1);
+ }
+
+ final SchemaReader aReader = new SchemaReader(new File(aArgumentList[0]));
+ aReader.Run();
+ }
+
+
+
+
+ private SchemaReader (final File aDriverFile)
+ {
+ maSchemaBase = new SchemaBase();
+ maTopLevelSchemas = new HashMap<>();
+ maMainSchemaFiles = new Vector<>();
+ maSchemaFiles = new HashSet<>();
+ maWorkList = new LinkedList<>();
+ maOutputOperations = new Vector<>();
+ mnTotalLineCount = 0;
+ mnTotalByteCount = 0;
+
+ ParseDriverFile(aDriverFile);
+ }
+
+
+
+
+ /** Read and parse the driver file that specifies which schema files to read
+ * and where the output should go.
+ */
+ private void ParseDriverFile (final File aDriverFile)
+ {
+ if (aDriverFile == null || ! aDriverFile.exists() || ! aDriverFile.canRead())
+ {
+ System.err.printf("can not read driver file\n");
+ System.exit(1);
+ }
+
+ try
+ {
+ final BufferedReader aIn = new BufferedReader(new FileReader(aDriverFile));
+ while(true)
+ {
+ String sLine = aIn.readLine();
+ if (sLine == null)
+ break;
+ // Lines starting with # are comment lines and are ignored.
+ if (sLine.matches("^\\s*#.*"))
+ continue;
+ // Lines containing only whitespace are also ignored.
+ else if (sLine.matches("^\\s*$"))
+ continue;
+
+ // Handle line continuation.
+ while (sLine.endsWith("\\"))
+ sLine = sLine.substring(0, sLine.length()-1) + aIn.readLine();
+
+ final Vector<String> aParts = SplitLine(sLine);
+ switch (aParts.get(0))
+ {
+ case "schema":
+ maMainSchemaFiles.add(new String[]{aParts.get(1), aParts.get(2)});
+ break;
+
+ case "output-schema":
+ maOutputOperations.add(new Runnable()
+ {
+ final File maFile = CreateCheckedOutputFile(aParts.get(1));
+ @Override public void run()
+ {
+ WriteSchema(maFile);
+ }
+ });
+ break;
+
+ case "output-optimized-schema":
+ maOutputOperations.add(new Runnable()
+ {
+ final File maFile = CreateCheckedOutputFile(aParts.get(1));
+ @Override public void run()
+ {
+ WriteOptimizedSchema(maFile);
+ }
+ });
+ break;
+
+ case "output-nonvalidating-parse-tables":
+ maOutputOperations.add(new Runnable()
+ {
+ final File aAutomatonLogFile = CreateCheckedOutputFile(aParts.get(1));
+ final File aSimpleTypeLogFile = CreateCheckedOutputFile(aParts.get(2));
+ final File aParseTableFile = CreateCheckedOutputFile(aParts.get(3));
+ @Override public void run()
+ {
+ WriteNonValidatingParseTables(
+ aAutomatonLogFile,
+ aSimpleTypeLogFile,
+ aParseTableFile);
+ }
+ });
+ break;
+
+ case "output-validating-parse-tables":
+ maOutputOperations.add(new Runnable()
+ {
+ final File aAutomatonLogFile = CreateCheckedOutputFile(aParts.get(1));
+ final File aSimpleTypeLogFile = CreateCheckedOutputFile(aParts.get(2));
+ final File aParseTableFile = CreateCheckedOutputFile(aParts.get(3));
+ @Override public void run()
+ {
+ WriteValidatingParseTables(
+ aAutomatonLogFile,
+ aSimpleTypeLogFile,
+ aParseTableFile);
+ }
+ });
+ break;
+
+ case "output-html-page":
+ maOutputOperations.add(new Runnable()
+ {
+ final File aHTMLPageFile = CreateCheckedOutputFile(aParts.get(1));
+ @Override public void run()
+ {
+ WriteHTMLPage(aHTMLPageFile);
+ }
+ });
+ break;
+
+ default:
+ System.err.printf("unknown command '%s' in driver file", aParts.get(0));
+ System.exit(1);
+ }
+ }
+ aIn.close();
+ }
+ catch (final Exception aException)
+ {
+ aException.printStackTrace();
+ }
+ }
+
+
+
+
+ private void Run ()
+ {
+ try
+ {
+ ParseSchemaFiles();
+ }
+ catch (final Exception aException)
+ {
+ aException.printStackTrace();
+ }
+
+ maOptimizedSchemaBase = maSchemaBase.GetOptimizedSchema(maTopLevelSchemas.values());
+ for (final Entry<String, Schema> aEntry : maTopLevelSchemas.entrySet())
+ aEntry.setValue(aEntry.getValue().GetOptimizedSchema(maOptimizedSchemaBase));
+
+ System.out.printf(" optimization left %d complex types and %d simple types\n",
+ maOptimizedSchemaBase.ComplexTypes.GetCount(),
+ maOptimizedSchemaBase.SimpleTypes.GetCount());
+
+ for (final Runnable aOperation : maOutputOperations)
+ {
+ aOperation.run();
+ }
+ }
+
+
+
+
+ private void ParseSchemaFiles ()
+ throws XMLStreamException
+ {
+ System.out.printf("parsing %d main schema files\n", maMainSchemaFiles.size());
+
+ for (final String[] aEntry : maMainSchemaFiles)
+ {
+ final String sMainSchemaShortname = aEntry[0];
+ final String sMainSchemaFile = aEntry[1];
+ final File aMainSchemaFile = new File(sMainSchemaFile);
+ if ( ! aMainSchemaFile.exists())
+ {
+ System.err.printf(" schema file does not exist\n");
+ System.exit(1);
+ }
+ if ( ! aMainSchemaFile.canRead())
+ {
+ System.err.printf("can not read schema file\n");
+ System.exit(1);
+ }
+
+ final Schema aSchema = new Schema(sMainSchemaShortname, maSchemaBase);
+ ParseSchemaFile(sMainSchemaFile, aSchema);
+ maTopLevelSchemas.put(sMainSchemaShortname, aSchema);
+ }
+
+ long nStartTime = System.currentTimeMillis();
+ while ( ! maWorkList.isEmpty())
+ {
+ ParseSchemaFile(maWorkList.poll(), null);
+ }
+ long nEndTime = System.currentTimeMillis();
+
+ System.out.printf("parsed %d schema files with a total of %d lines and %d bytes in %fs\n",
+ maSchemaFiles.size(),
+ mnTotalLineCount,
+ mnTotalByteCount,
+ (nEndTime-nStartTime)/1000.0);
+ System.out.printf(" found %d complex types and %d simple types\n",
+ maSchemaBase.ComplexTypes.GetCount(),
+ maSchemaBase.SimpleTypes.GetCount());
+
+ int nTopLevelElementCount = 0;
+ for (final Schema aSchema : maTopLevelSchemas.values())
+ nTopLevelElementCount += aSchema.TopLevelElements.GetCount();
+ System.out.printf(" the %d top level schemas have %d elements\n",
+ maTopLevelSchemas.size(),
+ nTopLevelElementCount);
+ }
+
+
+
+
+ private void ParseSchemaFile (
+ final String sSchemaFilename,
+ final Schema aSchema)
+ throws XMLStreamException
+ {
+ System.out.printf("parsing %s\n", sSchemaFilename);
+ maSchemaFiles.add(sSchemaFilename);
+
+ final SchemaParser aParser = new SchemaParser(new File(sSchemaFilename), aSchema, maSchemaBase);
+ aParser.Parse();
+
+ mnTotalLineCount += aParser.GetLineCount();
+ mnTotalByteCount += aParser.GetByteCount();
+ for (final File aFile : aParser.GetImportedSchemaFilenames())
+ AddSchemaReference(aFile.getAbsolutePath());
+ }
+
+
+
+
+ private void AddSchemaReference (final String sSchemaFilename)
+ {
+ if ( ! maSchemaFiles.contains(sSchemaFilename))
+ {
+ if (sSchemaFilename == null)
+ throw new RuntimeException();
+
+ // We don't know yet the file name of the schema, so just store null to mark the schema name as 'known'.
+ maSchemaFiles.add(sSchemaFilename);
+ maWorkList.add(sSchemaFilename);
+ }
+ }
+
+
+
+
+ /** Split the given string at whitespace but not at whitespace inside double quotes.
+ *
+ */
+ private Vector<String> SplitLine (final String sLine)
+ {
+ final Vector<String> aParts = new Vector<>();
+
+ boolean bIsInsideQuotes = false;
+ for (final String sPart : sLine.split("\""))
+ {
+ if (bIsInsideQuotes)
+ aParts.add(sPart);
+ else
+ for (final String sInnerPart : sPart.split("\\s+"))
+ {
+ if (sInnerPart == null)
+ throw new RuntimeException();
+ else if ( ! sInnerPart.isEmpty())
+ aParts.add(sInnerPart);
+ }
+
+ bIsInsideQuotes = ! bIsInsideQuotes;
+ }
+
+ return aParts;
+ }
+
+
+
+
+ /** Create a File object for a given file name.
+ * Check that the file is writable, i.e. its directory exists and that if
+ * the file already exists it can be replaced.
+ * Throws a RuntimeException when a check fails.
+ */
+ private File CreateCheckedOutputFile (final String sFilename)
+ {
+ final File aFile = new File(sFilename);
+ if ( ! aFile.getParentFile().exists())
+ throw new RuntimeException("directory of "+sFilename+" does not exist: can not create file");
+ if (aFile.exists() && ! aFile.canWrite())
+ throw new RuntimeException("file "+sFilename+" already exists and can not be replaced");
+ return aFile;
+ }
+
+
+
+
+ private void WriteSchema (final File aOutputFile)
+ {
+ LogGenerator.Write(aOutputFile, maSchemaBase, maTopLevelSchemas.values());
+ }
+
+
+
+
+ private void WriteOptimizedSchema (final File aOutputFile)
+ {
+ LogGenerator.Write(aOutputFile, maOptimizedSchemaBase, maTopLevelSchemas.values());
+ }
+
+
+
+
+ private void WriteNonValidatingParseTables (
+ final File aAutomatonLogFile,
+ final File aSimpleTypeLogFile,
+ final File aParseTableFile)
+ {
+ long nStartTime = System.currentTimeMillis();
+ final NonValidatingCreator aCreator = new NonValidatingCreator(maOptimizedSchemaBase, aAutomatonLogFile);
+ FiniteAutomatonContainer aAutomatons = aCreator.Create(maTopLevelSchemas.values());
+ long nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d non-validating automatons with %d states and %d transitions in %fs\n",
+ aAutomatons.GetAutomatonCount(),
+ aAutomatons.GetStateCount(),
+ aAutomatons.GetTransitionCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+ nStartTime = System.currentTimeMillis();
+ final SimpleTypeContainer aSimpleTypes = SimpleTypeContainer.Create(
+ maOptimizedSchemaBase,
+ aSimpleTypeLogFile);
+ nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d simple type descriptions in %fs\n",
+ aSimpleTypes.GetSimpleTypeCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+ new ParserTablesGenerator(
+ aAutomatons,
+ maOptimizedSchemaBase.Namespaces,
+ aSimpleTypes,
+ maOptimizedSchemaBase.AttributeValueToIdMap)
+ .Generate(aParseTableFile);
+ }
+
+
+
+
+ private void WriteValidatingParseTables (
+ final File aAutomatonLogFile,
+ final File aSimpleTypeLogFile,
+ final File aParseTableFile)
+ {
+ long nStartTime = System.currentTimeMillis();
+ final ValidatingCreator aCreator = new ValidatingCreator(maOptimizedSchemaBase, aAutomatonLogFile);
+ FiniteAutomatonContainer aAutomatons = aCreator.Create();
+ long nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d validating stack automatons with %d states and %d transitions in %fs\n",
+ aAutomatons.GetAutomatonCount(),
+ aAutomatons.GetStateCount(),
+ aAutomatons.GetTransitionCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+
+ nStartTime = System.currentTimeMillis();
+ aAutomatons = aAutomatons.CreateDFAs();
+ nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d deterministic automatons with %d states and %d transitions in %fs\n",
+ aAutomatons.GetAutomatonCount(),
+ aAutomatons.GetStateCount(),
+ aAutomatons.GetTransitionCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+ nStartTime = System.currentTimeMillis();
+ aAutomatons = aAutomatons.MinimizeDFAs();
+ nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "minimized automaton in %fs, there are now %d states and %d transitions\n",
+ (nEndTime-nStartTime)/1000.0,
+ aAutomatons.GetStateCount(),
+ aAutomatons.GetTransitionCount());
+
+ nStartTime = System.currentTimeMillis();
+ final SimpleTypeContainer aSimpleTypes = SimpleTypeContainer.Create(
+ maOptimizedSchemaBase,
+ aSimpleTypeLogFile);
+ nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d simple type descriptions in %fs\n",
+ aSimpleTypes.GetSimpleTypeCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+ new ParserTablesGenerator(
+ aAutomatons,
+ maOptimizedSchemaBase.Namespaces,
+ aSimpleTypes,
+ maOptimizedSchemaBase.AttributeValueToIdMap)
+ .Generate(aParseTableFile);
+ }
+
+
+
+
+ private void WriteHTMLPage (
+ final File aHTMLPageFile)
+ {
+ long nStartTime = System.currentTimeMillis();
+
+ new HtmlGenerator(maOptimizedSchemaBase, maTopLevelSchemas, aHTMLPageFile).Generate();
+
+ long nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created HTML page in %fs\n",
+ (nEndTime-nStartTime)/1000.0);
+ }
+
+
+
+
+ private final SchemaBase maSchemaBase;
+ private SchemaBase maOptimizedSchemaBase;
+ private final Map<String,Schema> maTopLevelSchemas;
+ private final Vector<String[]> maMainSchemaFiles;
+ private final Queue<String> maWorkList;
+ private final Vector<Runnable> maOutputOperations;
+ private final Set<String> maSchemaFiles;
+ private int mnTotalLineCount;
+ private int mnTotalByteCount;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/Test.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/Test.java
new file mode 100644
index 000000000000..5cfb3663aaca
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/Test.java
@@ -0,0 +1,81 @@
+/**************************************************************
+*
+* 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;
+
+import org.apache.openoffice.ooxml.schema.automaton.HopcroftMinimizer;
+import org.apache.openoffice.ooxml.schema.automaton.State;
+import org.apache.openoffice.ooxml.schema.automaton.StateContainer;
+import org.apache.openoffice.ooxml.schema.automaton.StateContext;
+import org.apache.openoffice.ooxml.schema.automaton.Transition;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** A simple test of the minimization algorithm for DFAs.
+ *
+ * May lead to the use of a testing framework in the future.
+ */
+public class Test
+{
+ public static void main (final String ... aArgumentList)
+ {
+ new Test("S", new String[]{"E"}, new String[][]{
+ {"S", "A", "a"},
+ {"A", "B", "b"},
+ {"A", "C", "b"},
+ {"B", "E", "c"},
+ {"C", "E", "c"},
+ });
+ }
+ private Test (
+ final String sStartState,
+ final String[] aAcceptingStates,
+ final String[][] aTransitions)
+ {
+ final StateContainer aOriginalStateContainer = new StateContainer();
+ final StateContext aStates = new StateContext(
+ aOriginalStateContainer,
+ sStartState);
+ for (final String sAcceptingState : aAcceptingStates)
+ {
+ final State s = aStates.CreateState(sAcceptingState);
+ s.SetIsAccepting();
+ }
+ for (final String[] aTransition : aTransitions)
+ {
+ final State start = aStates.GetOrCreateState(
+ new QualifiedName(aTransition[0]),
+ null);
+ final State end = aStates.GetOrCreateState(
+ new QualifiedName(aTransition[1]),
+ null);
+ final QualifiedName element = new QualifiedName(aTransition[2]);
+ final String type = "T_"+aTransition[2];
+
+ start.AddTransition(new Transition(start, end, element, type));
+ }
+ HopcroftMinimizer.MinimizeDFA (
+ new StateContainer(),
+ aStates,
+ null,
+ null,
+ System.out);
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/CreatorBase.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/CreatorBase.java
new file mode 100644
index 000000000000..7f93ece2d00c
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/CreatorBase.java
@@ -0,0 +1,124 @@
+/**************************************************************
+*
+* 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.HashSet;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.iterator.AttributeIterator;
+import org.apache.openoffice.ooxml.schema.iterator.DereferencingNodeIterator;
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Base class of the creator classes for DFAs and NFAs.
+ */
+public class CreatorBase
+{
+ CreatorBase (
+ final SchemaBase aSchemaBase,
+ final File aLogFile)
+ {
+ maSchemaBase = aSchemaBase;
+ maStateContainer = new StateContainer();
+ maLog = new Log(aLogFile);
+ msLogIndentation = "";
+ maElementSimpleTypes = new HashSet<>();
+ }
+
+
+
+
+ /** Create a very simple automaton:
+ * a) Its start state is also the accepting state.
+ * b) It does not allow any transitions.
+ * c) Its text items have the given simple type.
+ */
+ protected FiniteAutomaton CreateForSimpleType (final INode aSimpleType)
+ {
+ final StateContext aStateContext = new StateContext(
+ maStateContainer,
+ aSimpleType.GetName().GetStateName());
+ aStateContext.GetStartState().SetIsAccepting();
+ aStateContext.GetStartState().SetTextType(aSimpleType);
+ return new FiniteAutomaton(
+ aStateContext,
+ new Vector<Attribute>(),
+ aSimpleType.GetLocation());
+ }
+
+
+
+
+ protected Vector<Attribute> CollectAttributes (final INode aRoot)
+ {
+ final Vector<Attribute> aAttributes = new Vector<>();
+ for (final INode aNode : new DereferencingNodeIterator(aRoot, maSchemaBase, true))
+ for (final Attribute aAttribute : new AttributeIterator(aNode, maSchemaBase))
+ aAttributes.add(aAttribute);
+ return aAttributes;
+ }
+
+
+
+
+ protected void AddSkipTransition (
+ final State aState,
+ final SkipData aSkipData)
+ {
+ aState.AddSkipData(aSkipData);
+
+ if (maLog != null)
+ {
+ maLog.printf("%sskip state %s\n",
+ msLogIndentation,
+ aState.GetFullname());
+ }
+ }
+
+
+
+
+ protected void ProcessAttributes (final INode aNode)
+ {
+ for (final Attribute aAttribute : new AttributeIterator(aNode, maSchemaBase))
+ {
+ maLog.printf("%sattribute %s\n",
+ msLogIndentation,
+ aAttribute.GetName().GetDisplayName());
+ maAttributes.add(aAttribute);
+ }
+ }
+
+
+
+
+ protected final SchemaBase maSchemaBase;
+ protected final StateContainer maStateContainer;
+ protected final Log maLog;
+ protected String msLogIndentation;
+ protected Vector<Attribute> maAttributes;
+ protected final Set<INode> maElementSimpleTypes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/DFACreator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/DFACreator.java
new file mode 100644
index 000000000000..c6684acfbb53
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/DFACreator.java
@@ -0,0 +1,280 @@
+/**************************************************************
+*
+* 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.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Convert an NFA into a DFA via the powerset construction (also called subset
+ * construction).
+ */
+public class DFACreator
+{
+ /** For a given non-deterministic finite automaton create an equivalent
+ * deterministic finite automaton.
+ */
+ public static FiniteAutomaton CreateDFAforNFA (
+ final StateContainer aDFAStateContainer,
+ final StateContext aNFAStateContext,
+ final Vector<Attribute> aAttributes,
+ final QualifiedName aTypeName,
+ final Location aLocation)
+ {
+ final DFACreator aCreator = new DFACreator(aDFAStateContainer, aNFAStateContext, aTypeName);
+ aCreator.CreateDFAforNFA();
+ return new FiniteAutomaton(
+ aCreator.maDFAStateContext,
+ aAttributes,
+ aLocation);
+ }
+
+
+
+
+ private DFACreator (
+ final StateContainer aDFAStateContainer,
+ final StateContext aNFAStateContext,
+ final QualifiedName aTypeName)
+ {
+ maNFAStateContext = aNFAStateContext;
+
+ // Create the set of state sets where each element corresponds to a
+ // state in the DFA.
+ maNFASetToDFAStateMap = new TreeMap<>();
+ maDFAStateContext = new StateContext(
+ aDFAStateContainer,
+ aTypeName == null
+ ? "<TOP-LEVEL>"
+ : aTypeName.GetStateName());
+
+ maDFATransitions = new HashSet<>();
+ maAcceptingDFAStates = new Vector<>();
+ }
+
+
+
+
+ private void CreateDFAforNFA ()
+ {
+ final State aNFAStartState = maNFAStateContext.GetStartState();
+
+ // Initialize the creation process by adding the epsilon closure of the
+ // original start state to the work list.
+ final StateSet aStartSet = GetEpsilonClosure(new StateSet(aNFAStartState));
+ maNFASetToDFAStateMap.put(aStartSet, maDFAStateContext.GetStartState());
+
+ PropagateStateFlags(aStartSet, maDFAStateContext.GetStartState());
+
+ final Queue<StateSet> aWorklist = new LinkedList<>();
+ aWorklist.add(aStartSet);
+
+ while ( ! aWorklist.isEmpty())
+ {
+ final Collection<StateSet> aAdditionalWorkList = ProcessTransitionFront(
+ aWorklist.poll());
+
+ aWorklist.addAll(aAdditionalWorkList);
+ }
+ }
+
+
+
+
+ private Collection<StateSet> ProcessTransitionFront (
+ final StateSet aSet)
+ {
+ final Set<StateSet> aLocalWorklist = new TreeSet<>();
+
+ // Find all regular transitions that start from any state in the set.
+ final Map<String,Vector<Transition>> aTransitions = GetTransitionFront(aSet);
+
+ // Create new state sets for states that are reachable via the same element and
+ // the following epsilon transitions.
+ for (final Entry<String,Vector<Transition>> aEntry : aTransitions.entrySet())
+ {
+ // Create new state sets for both the end state of the transition.
+ final StateSet aEpsilonClosure = GetEpsilonClosure(GetEndStateSet(aEntry.getValue()));
+
+ // When these are new state sets then add them to the worklist
+ // and the set of sets.
+ State aDFAState = maNFASetToDFAStateMap.get(aEpsilonClosure);
+ if (aDFAState == null)
+ {
+ aLocalWorklist.add(aEpsilonClosure);
+ aDFAState = aEpsilonClosure.CreateStateForStateSet(maDFAStateContext);
+ PropagateStateFlags(aEpsilonClosure, aDFAState);
+ maNFASetToDFAStateMap.put(aEpsilonClosure, aDFAState);
+ if (aDFAState.IsAccepting())
+ maAcceptingDFAStates.add(aDFAState);
+ }
+
+ final State aStartState = maNFASetToDFAStateMap.get(aSet);
+ final QualifiedName aElementName = GetElementName(aEntry.getValue());
+ final String sElementTypeName = GetElementTypeName(aEntry.getValue());
+ assert(aElementName != null);
+ final Transition aTransition = new Transition(
+ aStartState,
+ aDFAState,
+ aElementName,
+ sElementTypeName);
+ aStartState.AddTransition(aTransition);
+ maDFATransitions.add(aTransition);
+ }
+
+ return aLocalWorklist;
+ }
+
+
+
+
+ private QualifiedName GetElementName (final Vector<Transition> aTransitions)
+ {
+ for (final Transition aTransition : aTransitions)
+ return aTransition.GetElementName();
+ return null;
+ }
+
+
+
+
+ private String GetElementTypeName (final Vector<Transition> aTransitions)
+ {
+ for (final Transition aTransition : aTransitions)
+ return aTransition.GetElementTypeName();
+ return null;
+ }
+
+
+
+
+ /** Return the epsilon closure of the given set of states.
+ * The result is the set of all states that are reachable via zero, one or
+ * more epsilon transitions from at least one state in the given set of
+ * states.
+ */
+ private StateSet GetEpsilonClosure ( final StateSet aSet)
+ {
+ final StateSet aClosure = new StateSet(aSet);
+
+ final Queue<State> aWorkList = new LinkedList<>();
+ for (final State aState : aSet.GetStates())
+ aWorkList.add(aState);
+
+ while( ! aWorkList.isEmpty())
+ {
+ final State aState = aWorkList.poll();
+ for (final EpsilonTransition aTransition : aState.GetEpsilonTransitions())
+ {
+ final State aEndState = aTransition.GetEndState();
+ if ( ! aClosure.ContainsState(aEndState))
+ {
+ aClosure.AddState(aEndState);
+ aWorkList.add(aEndState);
+ }
+ }
+ }
+
+ return aClosure;
+ }
+
+
+
+
+ /** Return the list of regular transitions (i.e. not epsilon transitions)
+ * that start from any of the states in the given set.
+ * The returned map is a partition of the transitions according to their
+ * triggering XML element.
+ */
+ private Map<String, Vector<Transition>> GetTransitionFront (final StateSet aSet)
+ {
+ final Map<String, Vector<Transition>> aTransitions = new HashMap<>();
+
+ for (final State aState : aSet.GetStates())
+ for (final Transition aTransition : aState.GetTransitions())
+ {
+ final String sElementName;
+ final QualifiedName aElementName = aTransition.GetElementName();
+ if (aElementName != null)
+ sElementName = aElementName.GetDisplayName();
+ else
+ sElementName = null; // For skip transitions.
+
+ Vector<Transition> aElementTransitions = aTransitions.get(sElementName);
+ if (aElementTransitions == null)
+ {
+ aElementTransitions = new Vector<>();
+ aTransitions.put(sElementName, aElementTransitions);
+ }
+ aElementTransitions.add(aTransition);
+ }
+ return aTransitions;
+ }
+
+
+
+
+ /** Return a state set that contains all end states of all the given transitions.
+ */
+ private StateSet GetEndStateSet (final Iterable<Transition> aTransitions)
+ {
+ final StateSet aStateSet = new StateSet();
+ for (final Transition aTransition : aTransitions)
+ aStateSet.AddState(aTransition.GetEndState());
+ return aStateSet;
+ }
+
+
+
+
+ /** Propagate accepting state flag and skip data.
+ */
+ private void PropagateStateFlags (
+ final StateSet aNFAStateSet,
+ final State aDFAState)
+ {
+ for (final State aNFAState : aNFAStateSet.GetStates())
+ aDFAState.CopyFrom(aNFAState);
+ }
+
+
+
+
+ private final StateContext maNFAStateContext;
+
+ private final Map<StateSet,State> maNFASetToDFAStateMap;
+ private final StateContext maDFAStateContext;
+ private final Set<Transition> maDFATransitions;
+ private final Vector<State> maAcceptingDFAStates;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/EpsilonTransition.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/EpsilonTransition.java
new file mode 100644
index 000000000000..75dca97ed6eb
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/EpsilonTransition.java
@@ -0,0 +1,70 @@
+/**************************************************************
+*
+* 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;
+
+/** Transition from one state to another that does not consume an input token.
+ *
+ * Use in the process of creating a validating parser.
+ */
+public class EpsilonTransition
+{
+ EpsilonTransition (
+ final State aStartState,
+ final State aEndState)
+ {
+ maStartState = aStartState;
+ maEndState = aEndState;
+ }
+
+
+
+
+ public State GetStartState ()
+ {
+ return maStartState;
+ }
+
+
+
+
+ public State GetEndState ()
+ {
+ return maEndState;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("%s -> %s",
+ maStartState.GetFullname(),
+ maEndState.GetFullname());
+ }
+
+
+
+
+ private final State maStartState;
+ private final State maEndState;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomaton.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomaton.java
new file mode 100644
index 000000000000..16bf2f737c8d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomaton.java
@@ -0,0 +1,169 @@
+/**************************************************************
+*
+* 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.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+
+/** Represents a DFA (deterministic FA) or a NFA (non-deterministic FA).
+ * There is one automaton for each complex type and one for the top level elements.
+ * Transitions correspond to 'element' elements in the schema or a start tag in
+ * the input file. During parsing the current automaton is pushed on a stack
+ * and the automaton that represents the complex type associated with the
+ * starting element is made the current automaton. An end tag pops an automaton
+ * from the stack and replaces the current automaton with it.
+ */
+public class FiniteAutomaton
+{
+ FiniteAutomaton (
+ final StateContext aContext,
+ final Vector<Attribute> aAttributes,
+ final Location aLocation)
+ {
+ maStateContext = aContext;
+ maAttributes = aAttributes!=null
+ ? aAttributes
+ : new Vector<Attribute>();
+ maLocation = aLocation;
+ }
+
+
+
+
+ public int GetStateCount ()
+ {
+ return maStateContext.GetStateCount();
+ }
+
+
+
+
+ public Iterable<State> GetStates()
+ {
+ return maStateContext.GetStates();
+ }
+
+
+
+
+ public Iterable<State> GetStatesSorted ()
+ {
+ return maStateContext.GetStatesSorted();
+ }
+
+
+
+
+ public State GetStartState ()
+ {
+ return maStateContext.GetStartState();
+ }
+
+
+
+
+ public Iterable<State> GetAcceptingStates ()
+ {
+ return maStateContext.GetAcceptingStates();
+ }
+
+
+
+
+ public FiniteAutomaton CreateDFA (
+ final StateContainer aDFAContainer,
+ final QualifiedName aTypeName)
+ {
+ return DFACreator.CreateDFAforNFA(
+ aDFAContainer,
+ maStateContext,
+ maAttributes,
+ aTypeName,
+ maLocation);
+ }
+
+
+
+
+ public StateContext GetStateContext()
+ {
+ return maStateContext;
+ }
+
+
+
+
+ public Iterable<Transition> GetTransitions ()
+ {
+ final Vector<Transition> aTransitions = new Vector<>();
+ for (final State aState : maStateContext.GetStates())
+ for (final Transition aTransition : aState.GetTransitions())
+ aTransitions.add(aTransition);
+ return aTransitions;
+ }
+
+
+
+
+ public int GetTransitionCount()
+ {
+ int nTransitionCount = 0;
+ for (final State aState : maStateContext.GetStates())
+ nTransitionCount += aState.GetTransitionCount();
+ return nTransitionCount;
+ }
+
+
+
+
+ public String GetTypeName ()
+ {
+ return maStateContext.GetStartState().GetFullname();
+ }
+
+
+
+
+ public Location GetLocation ()
+ {
+ return maLocation;
+ }
+
+
+
+
+ public Vector<Attribute> GetAttributes ()
+ {
+ return maAttributes;
+ }
+
+
+
+
+ private final StateContext maStateContext;
+ private final Vector<Attribute> maAttributes;
+ private final Location maLocation;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomatonContainer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomatonContainer.java
new file mode 100644
index 000000000000..e76b7e8614e7
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomatonContainer.java
@@ -0,0 +1,166 @@
+/**************************************************************
+*
+* 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.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** As there is one FA for each complex type and one for the top level elements,
+ * this container represents the whole set of schemas.
+ */
+public class FiniteAutomatonContainer
+{
+ FiniteAutomatonContainer (final StateContainer aStateContainer)
+ {
+ maComplexTypeNameToAutomatonMap = new HashMap<>();
+ }
+
+
+
+
+ public void AddAutomaton (
+ final QualifiedName aElementName,
+ final FiniteAutomaton aAutomaton)
+ {
+ maComplexTypeNameToAutomatonMap.put(aElementName, aAutomaton);
+ }
+
+
+
+
+ public Iterable<FiniteAutomaton> GetAutomatons()
+ {
+ return maComplexTypeNameToAutomatonMap.values();
+ }
+
+
+
+
+ public int GetAutomatonCount ()
+ {
+ return maComplexTypeNameToAutomatonMap.size();
+ }
+
+
+
+
+ public Iterable<State> GetStates()
+ {
+ final Vector<State> aStates = new Vector<>();
+ for (final FiniteAutomaton aAutomaton : maComplexTypeNameToAutomatonMap.values())
+ for (final State aState : aAutomaton.GetStates())
+ aStates.add(aState);
+ return aStates;
+ }
+
+
+
+
+ public int GetStateCount()
+ {
+ int nStateCount = 0;
+ for (final FiniteAutomaton aAutomaton : maComplexTypeNameToAutomatonMap.values())
+ nStateCount += aAutomaton.GetStateCount();
+ return nStateCount;
+ }
+
+
+
+
+ public int GetTransitionCount ()
+ {
+ int nTransitionCount = 0;
+ for (final FiniteAutomaton aAutomaton : maComplexTypeNameToAutomatonMap.values())
+ nTransitionCount += aAutomaton.GetTransitionCount();
+ return nTransitionCount;
+ }
+
+
+
+
+ public FiniteAutomatonContainer CreateDFAs ()
+ {
+ final StateContainer aDFAStateContainer = new StateContainer();
+ final FiniteAutomatonContainer aDFAs = new FiniteAutomatonContainer(aDFAStateContainer);
+ for (final Entry<QualifiedName, FiniteAutomaton> aEntry : maComplexTypeNameToAutomatonMap.entrySet())
+ {
+ aDFAs.AddAutomaton(
+ aEntry.getKey(),
+ aEntry.getValue().CreateDFA(
+ aDFAStateContainer,
+ aEntry.getKey()));
+ }
+ return aDFAs;
+ }
+
+
+
+
+ public FiniteAutomatonContainer MinimizeDFAs ()
+ {
+ PrintStream aLog = null;
+ try
+ {
+ aLog = new PrintStream(new FileOutputStream(new File("/tmp/minimization.log")));
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+
+ final StateContainer aNewStateContainer = new StateContainer();
+ final FiniteAutomatonContainer aDFAs = new FiniteAutomatonContainer(aNewStateContainer);
+ for (final Entry<QualifiedName, FiniteAutomaton> aEntry : maComplexTypeNameToAutomatonMap.entrySet())
+ {
+ aDFAs.AddAutomaton(
+ aEntry.getKey(),
+ HopcroftMinimizer.MinimizeDFA(
+ aNewStateContainer,
+ aEntry.getValue().GetStateContext(),
+ aEntry.getValue().GetAttributes(),
+ aEntry.getValue().GetLocation(),
+ aLog));
+ }
+ return aDFAs;
+ }
+
+
+
+
+ public FiniteAutomaton GetTopLevelAutomaton ()
+ {
+ return maComplexTypeNameToAutomatonMap.get(null);
+ }
+
+
+
+
+ private final Map<QualifiedName, FiniteAutomaton> maComplexTypeNameToAutomatonMap;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/HopcroftMinimizer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/HopcroftMinimizer.java
new file mode 100644
index 000000000000..9177ccc707ae
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/HopcroftMinimizer.java
@@ -0,0 +1,380 @@
+/**************************************************************
+*
+* 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.PrintStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Minimize an DFA with respect to its number of states.
+ * This is most important for the use of the 'all' element in the OOXML
+ * specification which leads to a lot of additional states and transitions.
+ */
+public class HopcroftMinimizer
+{
+ /** Create a DFA that is equivalent to a given DFA but has the minimal
+ * number of states.
+ */
+ public static FiniteAutomaton MinimizeDFA (
+ final StateContainer aNewStateContainer,
+ final StateContext aOriginalStates,
+ final Vector<Attribute> aAttributes,
+ final Location aLocation,
+ final PrintStream aLog)
+ {
+ if (aLog != null)
+ {
+ aLog.printf("minimizing %d states and %d transitions\n",
+ aOriginalStates.GetStateCount(),
+ aOriginalStates.GetTransitionCount());
+ DisplayStates(aOriginalStates, aLog);
+ }
+
+ TreeSet<StateSet> aT = new TreeSet<>();
+ TreeSet<StateSet> aP = new TreeSet<>();
+ Map<State,StateSet> aTMap = new HashMap<>();
+ Map<State,StateSet> aPMap = new HashMap<>();
+ InitializeMap(aT, aTMap, aOriginalStates.GetStates());
+
+ // Split partitions until there is nothing else to do.
+ while ( ! AreSetsOfStateSetsEqual(aP, aT))
+ {
+ if (aLog != null)
+ aLog.printf("T has %d members\n", aT.size());
+
+ aP = aT;
+ aPMap = aTMap;
+ aT = new TreeSet<>();
+ aTMap = new HashMap<>();
+
+ for (final StateSet aSet : aP)
+ {
+ final Iterable<StateSet> aParts = Split(aSet, aP, aPMap);
+ if (aParts == null)
+ {
+ // No split necessary.
+ assert( ! aSet.IsEmpty());
+ aT.add(aSet);
+ for (final State aState : aSet.GetStates())
+ aTMap.put(aState, aSet);
+ }
+ else
+ {
+ for (final StateSet aPart : aParts)
+ {
+ assert( ! aPart.IsEmpty());
+ aT.add(aPart);
+
+ for (final State aState : aPart.GetStates())
+ aTMap.put(aState, aPart);
+ }
+ }
+ }
+ }
+
+ // Create new states.
+ final StateContext aMinimizedStates = CreateNewStates(
+ aP,
+ aPMap,
+ aNewStateContainer,
+ aOriginalStates);
+
+ if (aLog != null)
+ {
+ aLog.printf("to %d states and %d transitions\n",
+ aMinimizedStates.GetStateCount(),
+ aMinimizedStates.GetTransitionCount());
+ DisplayStates(aMinimizedStates, aLog);
+ for (final StateSet aSet : aT)
+ aLog.printf(" %s\n", aSet.toString());
+ }
+
+ // Create and return the new minimized automaton.
+ return new FiniteAutomaton(
+ aMinimizedStates,
+ aAttributes,
+ aLocation);
+ }
+
+
+
+
+ /** We start with two sets. One contains all start states (in our case
+ * just one), the other contains all other states.
+ */
+ private static void InitializeMap (
+ final Set<StateSet> aSet,
+ final Map<State,StateSet> aMap,
+ final Iterable<State> aStates)
+ {
+ final StateSet aAcceptingStates = new StateSet();
+ final StateSet aNonAcceptingStates = new StateSet();
+ for (final State aState : aStates)
+ {
+ if (aState.IsAccepting())
+ {
+ aAcceptingStates.AddState(aState);
+ aMap.put(aState, aAcceptingStates);
+ }
+ else
+ {
+ aNonAcceptingStates.AddState(aState);
+ aMap.put(aState, aNonAcceptingStates);
+ }
+ }
+ if (aAcceptingStates.IsEmpty())
+ throw new RuntimeException("there should be at least one accepting state");
+ aSet.add(aAcceptingStates);
+ if ( ! aNonAcceptingStates.IsEmpty())
+ aSet.add(aNonAcceptingStates);
+ }
+
+
+
+
+ private static Iterable<StateSet> Split (
+ final StateSet aSet,
+ final Set<StateSet> aT,
+ final Map<State,StateSet> aTMap)
+ {
+ if (aSet.GetStateCount() == 1)
+ return null;
+
+ final Set<QualifiedName> aElements = CollectElementNames(aSet);
+ for (final QualifiedName aElementName : aElements)
+ {
+ final Collection<StateSet> aPartitions = Split(aSet, aT, aTMap, aElementName);
+ if (aPartitions == null)
+ continue;
+ if (aPartitions.size() > 1)
+ return aPartitions;
+ }
+ return null;
+ }
+
+
+
+
+ /** Create a partition of the given set of states according to their
+ * transitions.
+ * All states whose transitions point to the same state set go in the same
+ * partition.
+ */
+ private static Collection<StateSet> Split (
+ final StateSet aSet,
+ final Set<StateSet> aT,
+ final Map<State,StateSet> aTMap,
+ final QualifiedName aElementName)
+ {
+ // Set up a forward map that does two steps:
+ // from s via transition regarding aElementName to s'
+ // from s' to a state set under aTMap(s).
+ final Map<State,StateSet> aForwardMap = new HashMap<>();
+ for (final State aState : aSet.GetStates())
+ {
+ final Transition aTransition = GetTransition(aState, aElementName);
+ if (aTransition == null)
+ aForwardMap.put(aState, null);
+ else
+ aForwardMap.put(aState, aTMap.get(aTransition.GetEndState()));
+ }
+
+ // Create the partion of aSet according to aForwardMap. All states that map
+ // to the same element go into the same state set.
+ if (aForwardMap.size() == 1)
+ {
+ // No split necessary.
+ return null;
+ }
+ else
+ {
+ // Set up a reverse map that maps that maps the values in aForwardMap to
+ // new state sets whose contents are the keys in aForwardMap.
+ final Map<StateSet,StateSet> aReverseMap = new HashMap<>();
+ for (final Entry<State,StateSet> aEntry : aForwardMap.entrySet())
+ {
+ StateSet aPartitionSet = aReverseMap.get(aEntry.getValue());
+ if (aPartitionSet == null)
+ {
+ aPartitionSet = new StateSet();
+ aReverseMap.put(aEntry.getValue(), aPartitionSet);
+ }
+ aPartitionSet.AddState(aEntry.getKey());
+ }
+ return aReverseMap.values();
+ }
+ }
+
+
+
+
+ private static Transition GetTransition (
+ final State aState,
+ final QualifiedName aElementName)
+ {
+ Transition aTransition = null;
+ for (final Transition aCandidate : aState.GetTransitions())
+ if (aCandidate.GetElementName().compareTo(aElementName) == 0)
+ {
+ assert(aTransition==null);
+ aTransition = aCandidate;
+ // break;
+ }
+ return aTransition;
+ }
+
+
+
+
+ private static Set<QualifiedName> CollectElementNames (final StateSet aSet)
+ {
+ final Set<QualifiedName> aNames = new TreeSet<>();
+ for (final State aState : aSet.GetStates())
+ for (final Transition aTransition : aState.GetTransitions())
+ aNames.add(aTransition.GetElementName());
+
+ return aNames;
+ }
+
+
+
+
+ private static boolean AreSetsOfStateSetsEqual (
+ final TreeSet<StateSet> aSetOfSetsA,
+ final TreeSet<StateSet> aSetOfSetsB)
+ {
+ if (aSetOfSetsA.size() != aSetOfSetsB.size())
+ return false;
+ else
+ {
+ final Iterator<StateSet> aSetIteratorA = aSetOfSetsA.iterator();
+ final Iterator<StateSet> aSetIteratorB = aSetOfSetsB.iterator();
+ while (aSetIteratorA.hasNext() && aSetIteratorB.hasNext())
+ {
+ if (aSetIteratorA.next().compareTo(aSetIteratorB.next()) != 0)
+ return false;
+ }
+ return true;
+ }
+ }
+
+
+
+
+ private static StateContext CreateNewStates (
+ final TreeSet<StateSet> aP,
+ final Map<State,StateSet> aPMap,
+ final StateContainer aNewStateContainer,
+ final StateContext aOriginalStates)
+ {
+ final StateContext aMinimizedStates = new StateContext(
+ aNewStateContainer,
+ aOriginalStates.GetStartState().GetFullname());
+
+ // Create the new states.
+ final Map<State,State> aOldStateToNewStateMap = new TreeMap<>();
+ for (final StateSet aSet : aP)
+ {
+ State aNewState = null;
+ for (final State aOldState : aSet.GetStates())
+ {
+ if (aNewState == null)
+ aNewState = aOldState.Clone(aMinimizedStates);
+ aOldStateToNewStateMap.put(aOldState, aNewState);
+ }
+ }
+
+ // Create the new transitions.
+ for (final StateSet aSet : aP)
+ {
+ final State aOldStartState = aSet.GetStates().iterator().next();
+ final State aNewStartState = aOldStateToNewStateMap.get(aOldStartState);
+
+ for (final Transition aTransition : aOldStartState.GetTransitions())
+ {
+ final State aOldEndState = aTransition.GetEndState();
+ final State aNewEndState = aOldStateToNewStateMap.get(aOldEndState);
+
+ // Check if the transition already exists.
+ if (HasTransition(aNewStartState, aTransition.GetElementName()))
+ continue;
+
+ aNewStartState.AddTransition(
+ new Transition(
+ aNewStartState,
+ aNewEndState,
+ aTransition.GetElementName(),
+ aTransition.GetElementTypeName()));
+ }
+ }
+
+ // Transfer skip data and accepting flags.
+ for (final State aOldState : aOriginalStates.GetStates())
+ {
+ final State aNewState = aOldStateToNewStateMap.get(aOldState);
+ aNewState.CopyFrom(aOldState);
+ }
+ return aMinimizedStates;
+ }
+
+
+
+
+ private static boolean HasTransition (
+ final State aState,
+ final QualifiedName aElementName)
+ {
+ for (final Transition aTransition : aState.GetTransitions())
+ if (aTransition.GetElementName().compareTo(aElementName) == 0)
+ return true;
+ return false;
+ }
+
+
+
+
+ private static void DisplayStates (
+ final StateContext aStates,
+ final PrintStream aLog)
+ {
+ for (final State aState : aStates.GetStates())
+ {
+ aLog.printf(" %s %s\n", aState.GetFullname(),
+ aState.IsAccepting() ? "is accepting" : "");
+ for (final Transition aTransition : aState.GetTransitions())
+ aLog.printf(" -> %s via %s\n",
+ aTransition.GetEndState().GetFullname(),
+ aTransition.GetElementName().GetStateName());
+ }
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/NonValidatingCreator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/NonValidatingCreator.java
new file mode 100644
index 000000000000..f96e3237a431
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/NonValidatingCreator.java
@@ -0,0 +1,212 @@
+/**************************************************************
+*
+* 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;
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/SkipData.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/SkipData.java
new file mode 100644
index 000000000000..f5c051caad4d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/SkipData.java
@@ -0,0 +1,54 @@
+/**************************************************************
+*
+* 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 org.apache.openoffice.ooxml.schema.model.complex.Any;
+
+/** Description of optional content that can be skipped when not supported.
+ * Corresponds to the 'any' schema element.
+ */
+public class SkipData
+{
+ public SkipData (
+ final Any.ProcessContents aProcessContents,
+ final String[] aNamespaces)
+ {
+ maProcessContents = aProcessContents;
+ maNamespaces = aNamespaces;
+ }
+
+
+
+
+ public SkipData Clone (final State aState)
+ {
+ return new SkipData(
+ maProcessContents,
+ maNamespaces);
+ }
+
+
+
+
+ final Any.ProcessContents maProcessContents;
+ final String[] maNamespaces;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/State.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/State.java
new file mode 100644
index 000000000000..7d9982c0e5c2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/State.java
@@ -0,0 +1,263 @@
+/**************************************************************
+*
+* 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.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Each complex type is represented by a State object (primary state).
+ * For a validating parser additional states are created for sequences, choices, etc. (secondary states).
+ * Secondary states have the same basename as primary states and suffixes to make their names unique.
+ * Full names of states contain both the basename and the suffix.
+ */
+public class State
+ implements Comparable<State>
+{
+ /** Create a new state from a basename and an optional suffix.
+ *
+ * Don't call this constructor directly. Use methods in StateContext instead.
+ * They ensure that states are unique per context.
+ */
+ State (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ maBasename = aBasename;
+ msSuffix = sSuffix;
+ msFullname = GetStateName(aBasename, msSuffix);
+ maTransitions = new Vector<>();
+ maEpsilonTransitions = new Vector<>();
+ maSkipData = new Vector<>();
+ mbIsAccepting = false;
+ maTextType = null;
+ }
+
+
+
+
+ State Clone (final StateContext aContext)
+ {
+ return aContext.GetOrCreateState(maBasename, msSuffix);
+ }
+
+
+
+
+ static String GetStateName (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ if (sSuffix == null)
+ return aBasename.GetStateName();
+ else
+ return aBasename.GetStateName()+"_"+sSuffix;
+ }
+
+
+
+
+ public String GetFullname ()
+ {
+ return msFullname;
+ }
+
+
+
+
+ public QualifiedName GetBasename ()
+ {
+ return maBasename;
+ }
+
+
+
+
+ /** Return a qualified name that contains the suffix.
+ * This is typically only used for sorting type names.
+ */
+ public QualifiedName GetQualifiedName ()
+ {
+ return new QualifiedName(
+ maBasename.GetNamespacePrefix(),
+ maBasename.GetNamespaceURI(),
+ msSuffix != null
+ ? maBasename.GetLocalPart() + "_" + msSuffix
+ : maBasename.GetLocalPart());
+ }
+
+
+
+
+ public String GetSuffix ()
+ {
+ return msSuffix;
+ }
+
+
+
+
+ public void AddTransition (final Transition aTransition)
+ {
+ assert(this == aTransition.GetStartState());
+ maTransitions.add(aTransition);
+ }
+
+
+
+
+ public Iterable<Transition> GetTransitions()
+ {
+ return maTransitions;
+ }
+
+
+
+
+ public int GetTransitionCount ()
+ {
+ return maTransitions.size();
+ }
+
+
+
+
+ public void AddEpsilonTransition (final EpsilonTransition aTransition)
+ {
+ assert(this == aTransition.GetStartState());
+ maEpsilonTransitions.add(aTransition);
+ }
+
+
+
+
+ public Iterable<EpsilonTransition> GetEpsilonTransitions()
+ {
+ return maEpsilonTransitions;
+ }
+
+
+
+
+ public void AddSkipData (final SkipData aSkipData)
+ {
+ maSkipData.add(aSkipData);
+ }
+
+
+
+
+ public Iterable<SkipData> GetSkipData ()
+ {
+ return maSkipData;
+ }
+
+
+
+
+ public void SetIsAccepting ()
+ {
+ mbIsAccepting = true;
+ }
+
+
+
+
+ public boolean IsAccepting ()
+ {
+ return mbIsAccepting;
+ }
+
+
+
+
+ /** The basename is the primary sort key. The suffix is the secondary key.
+ */
+ @Override
+ public int compareTo (final State aOther)
+ {
+ int nResult = maBasename.compareTo(aOther.maBasename);
+ if (nResult == 0)
+ {
+ if (msSuffix==null && aOther.msSuffix==null)
+ nResult = 0;
+ else if (msSuffix!=null && aOther.msSuffix!=null)
+ nResult = msSuffix.compareTo(aOther.msSuffix);
+ else if (msSuffix==null)
+ nResult = -1;
+ else
+ nResult = +1;
+ }
+ return nResult;
+ }
+
+
+
+
+ public void SetTextType (final INode aTextType)
+ {
+ assert(maTextType==null);
+ maTextType = aTextType;
+ }
+
+
+
+
+ public INode GetTextType ()
+ {
+ return maTextType;
+ }
+
+
+
+
+ public void CopyFrom (final State aOther)
+ {
+ if (aOther.IsAccepting())
+ SetIsAccepting();
+ for (final SkipData aSkipData : aOther.GetSkipData())
+ AddSkipData(aSkipData.Clone(this));
+ SetTextType(aOther.GetTextType());
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return msFullname;
+ }
+
+
+
+
+ private final QualifiedName maBasename;
+ private final String msSuffix;
+ private final String msFullname;
+ private final Vector<Transition> maTransitions;
+ private final Vector<EpsilonTransition> maEpsilonTransitions;
+ private final Vector<SkipData> maSkipData;
+ private boolean mbIsAccepting;
+ private INode maTextType;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContainer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContainer.java
new file mode 100644
index 000000000000..2a8df93c96d5
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContainer.java
@@ -0,0 +1,73 @@
+/**************************************************************
+*
+* 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.util.HashMap;
+import java.util.Map;
+
+/** A container of states that spans all StateContext objects that represent each
+ * a single complex type.
+ */
+public class StateContainer
+{
+ public StateContainer ()
+ {
+ maNameToStateMap = new HashMap<>();
+ }
+
+
+
+
+ boolean HasState (final String sFullname)
+ {
+ return maNameToStateMap.containsKey(sFullname);
+ }
+
+
+
+
+ State GetStateForFullname (final String sFullname)
+ {
+ return maNameToStateMap.get(sFullname);
+ }
+
+
+
+
+ public void AddState (final State aState)
+ {
+ maNameToStateMap.put(aState.GetFullname(), aState);
+ }
+
+
+
+
+ public void RemoveState (final State aState)
+ {
+ maNameToStateMap.remove(aState);
+ }
+
+
+
+
+ private final Map<String,State> maNameToStateMap;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContext.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContext.java
new file mode 100644
index 000000000000..f2d877f2bdc1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContext.java
@@ -0,0 +1,269 @@
+/**************************************************************
+*
+* 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.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Represents the set of states of a single complex type.
+ *
+ * Because states have to be unique, the state container is an object shared
+ * by all StateContext objects.
+ *
+ * There is a single start state but there can be more than one accepting state.
+ */
+public class StateContext
+{
+ public StateContext (
+ final StateContainer aStateContainer,
+ final String sBaseStateName)
+ {
+ maStateContainer = aStateContainer;
+ maStates = new HashSet<>();
+ maStartState = GetOrCreateState(new QualifiedName(null, null, sBaseStateName), null);
+ maDisambiguateCounters = new HashMap<>();
+ }
+
+
+
+
+ public State CreateState (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ final String sFullname = State.GetStateName(aBasename, sSuffix);
+ if (HasState(sFullname))
+ throw new RuntimeException("state with name '"+sFullname+"' can not be created because it already exists");
+ final State aState = new State(aBasename, sSuffix);
+ AddState(aState);
+ return aState;
+ }
+
+
+
+ public State CreateState (final String sBasename)
+ {
+ return CreateState(new QualifiedName(sBasename), null);
+ }
+
+
+
+
+ public State CreateState (
+ final State aState,
+ final String sSuffix)
+ {
+ if (sSuffix==null && aState.GetSuffix()==null)
+ return CreateState(aState.GetBasename(), null);
+ else if (sSuffix!=null && aState.GetSuffix()!=null)
+ return CreateState(aState.GetBasename(), aState.GetSuffix()+"_"+sSuffix);
+ else if (sSuffix != null)
+ return CreateState(aState.GetBasename(), sSuffix);
+ else
+ return CreateState(aState.GetBasename(), aState.GetSuffix());
+ }
+
+
+
+
+ public State GetState (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ return maStateContainer.GetStateForFullname(State.GetStateName(aBasename, sSuffix));
+ }
+
+
+
+
+ public State GetOrCreateState (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ State aState = GetState(aBasename, sSuffix);
+ if (aState == null)
+ {
+ aState = CreateState(aBasename, sSuffix);
+ AddState(aState);
+ }
+ return aState;
+ }
+
+
+
+
+ public State GetStartStateForTypeName (final QualifiedName aName)
+ {
+ return GetOrCreateState(aName, null);
+ }
+
+
+
+
+ public State CreateEndState ()
+ {
+ final State aEndState = CreateState(
+ maStartState.GetBasename(),
+ "end");
+ aEndState.SetIsAccepting();
+ return aEndState;
+ }
+
+
+
+ /** Some algorithms can not easily produce unique suffixes.
+ * Append an integer to the given suffix so that it becomes unique.
+ */
+ public String GetUnambiguousSuffix (final QualifiedName aBasename, final String sSuffix)
+ {
+ String sStateName = State.GetStateName(aBasename, sSuffix);
+ if ( ! HasState(sStateName))
+ {
+ // The given suffix can be used without modification.
+ return sSuffix;
+ }
+ else
+ {
+ int nIndex = 2;
+ final Integer nDisambiguateCounter = maDisambiguateCounters.get(sStateName);
+ if (nDisambiguateCounter != null)
+ nIndex = nDisambiguateCounter+1;
+ maDisambiguateCounters.put(sStateName, nIndex);
+
+ return sSuffix + "_" + nIndex;
+ }
+ }
+
+
+
+
+ public boolean HasState (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ return maStateContainer.HasState(State.GetStateName(aBasename, sSuffix));
+ }
+
+
+
+
+ /** Return whether a state with the given name already belongs to the state
+ * context.
+ */
+ public boolean HasState (final String sFullname)
+ {
+ return maStateContainer.HasState(sFullname);
+ }
+
+
+
+
+ /** The start state is the state a parser is in initially.
+ */
+ public State GetStartState ()
+ {
+ return maStartState;
+ }
+
+
+
+
+ public Iterable<State> GetAcceptingStates ()
+ {
+ final Vector<State> aAcceptingStates = new Vector<>();
+ for (final State aState : maStates)
+ if (aState.IsAccepting())
+ aAcceptingStates.add(aState);
+ return aAcceptingStates;
+ }
+
+
+
+
+ /** Add the given state to the state context.
+ */
+ public void AddState (final State aState)
+ {
+ maStateContainer.AddState(aState);
+ maStates.add(aState);
+ }
+
+
+
+
+ public void RemoveState (final State aState)
+ {
+ maStateContainer.RemoveState(aState);
+ maStates.remove(aState);
+ }
+
+
+
+
+ public int GetStateCount ()
+ {
+ return maStates.size();
+ }
+
+
+
+
+ public Iterable<State> GetStatesSorted()
+ {
+ final Set<State> aSortedStates = new TreeSet<>();
+ aSortedStates.addAll(maStates);
+ return aSortedStates;
+ }
+
+
+
+
+ public Iterable<State> GetStates()
+ {
+ return maStates;
+ }
+
+
+
+
+ public int GetTransitionCount ()
+ {
+ int nStateCount = 0;
+ for (final State aState : maStates)
+ nStateCount += aState.GetTransitionCount();
+ return nStateCount;
+ }
+
+
+
+
+ private final StateContainer maStateContainer;
+ private final Set<State> maStates;
+ private final State maStartState;
+ private final Map<String,Integer> maDisambiguateCounters;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateSet.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateSet.java
new file mode 100644
index 000000000000..bac2092104fe
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateSet.java
@@ -0,0 +1,245 @@
+/**************************************************************
+*
+* 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.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Used in the transformation of NFA to DFA and in the minimization of DFAs.
+ * References a set of regular states.
+ */
+public class StateSet
+ implements Comparable<StateSet>
+{
+ public StateSet ()
+ {
+ maStates = new TreeSet<>();
+ }
+
+
+
+
+ public StateSet (final State aState)
+ {
+ this();
+ maStates.add(aState);
+ }
+
+
+
+
+ public StateSet (final StateSet aSet)
+ {
+ this();
+ maStates.addAll(aSet.maStates);
+ }
+
+
+
+
+ public StateSet (final Iterable<State> aStates)
+ {
+ this();
+ for (final State aState : aStates)
+ maStates.add(aState);
+ }
+
+
+
+
+ public void AddState (final State aState)
+ {
+ maStates.add(aState);
+ }
+
+
+
+
+ public void AddStates (final StateSet aStates)
+ {
+ maStates.addAll(aStates.maStates);
+ }
+
+
+
+
+ public boolean IsDisjoint (final StateSet aOther)
+ {
+ for (final State aState : aOther.maStates)
+ if (maStates.contains(aState))
+ return false;
+ for (final State aState : maStates)
+ if (aOther.maStates.contains(aState))
+ return false;
+ return true;
+ }
+
+
+
+
+ public void RemoveState (final State aState)
+ {
+ maStates.remove(aState);
+ }
+
+
+
+
+ public Iterable<State> GetStates ()
+ {
+ return maStates;
+ }
+
+
+
+
+ public boolean ContainsState (final State aState)
+ {
+ return maStates.contains(aState);
+ }
+
+
+
+
+ public int GetStateCount ()
+ {
+ return maStates.size();
+ }
+
+
+
+
+ public boolean HasStates ()
+ {
+ return ! maStates.isEmpty();
+ }
+
+
+
+
+ public State CreateStateForStateSet (final StateContext aContext)
+ {
+ // Find a name for the new state. If there is type state in the given
+ // set then use its name.
+ QualifiedName aBaseName = null;
+ String sShortestSuffix = null;
+ for (final State aState : maStates)
+ {
+ final QualifiedName aName = aState.GetBasename();
+ final String sSuffix = aState.GetSuffix();
+
+ if (aBaseName == null)
+ {
+ aBaseName = aName;
+ sShortestSuffix = sSuffix;
+ }
+ else if (aBaseName.compareTo(aName) != 0)
+ {
+ System.out.printf("%s != %s\n", aBaseName, aName);
+ throw new RuntimeException("state set contains states with different base names: "+toString());
+ }
+
+ if (sShortestSuffix == null)
+ sShortestSuffix = sSuffix;
+ else if (sSuffix.length() < sShortestSuffix.length())
+ sShortestSuffix = sSuffix;
+ }
+ if (aBaseName == null)
+ throw new RuntimeException("can not create state for "+toString());
+
+ // Disambiguate new state name.
+ State aNewState = aContext.CreateState(
+ aBaseName,
+ aContext.GetUnambiguousSuffix(aBaseName, sShortestSuffix));
+ assert(aNewState!=null);
+
+ // Mark the new state as accepting if at least one of its original states
+ // is accepting.
+ for (final State aState : maStates)
+ {
+ if (aState.IsAccepting())
+ {
+ aNewState.SetIsAccepting();
+ break;
+ }
+ for (final SkipData aData : aState.GetSkipData())
+ aNewState.AddSkipData(aData.Clone(aNewState));
+ final INode aTextType = aState.GetTextType();
+ if (aTextType != null)
+ aNewState.SetTextType(aTextType);
+ }
+
+ return aNewState;
+ }
+
+
+
+
+ @Override
+ public int compareTo (final StateSet aOther)
+ {
+ final int nStateCount = maStates.size();
+
+ if (nStateCount != aOther.maStates.size())
+ return nStateCount - aOther.maStates.size();
+ else
+ {
+ final Iterator<State> aIterator = maStates.iterator();
+ final Iterator<State> aOtherIterator = aOther.maStates.iterator();
+ while (aIterator.hasNext())
+ {
+ final State aState = aIterator.next();
+ final State aOtherState = aOtherIterator.next();
+ final int nResult = aState.compareTo(aOtherState);
+ if (nResult != 0)
+ return nResult;
+ }
+ return 0;
+ }
+ }
+
+
+
+
+ public boolean IsEmpty()
+ {
+ return maStates.isEmpty();
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "set of "+maStates.size()+" states "+maStates.toString();
+ }
+
+
+
+
+ private final Set<State> maStates;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/Transition.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/Transition.java
new file mode 100644
index 000000000000..ffacb1ad5ef9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/Transition.java
@@ -0,0 +1,97 @@
+/**************************************************************
+*
+* 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 org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Each transition corresponds to an 'element' schema element.
+ * It moves from the start state to the end state when a certain start tag is
+ * processed. The element corresponds to another complex type which will be
+ * parsed during the transition.
+ */
+public class Transition
+{
+ public Transition (
+ final State aStartState,
+ final State aEndState,
+ final QualifiedName aElementName,
+ final String sElementTypeName)
+ {
+ maStartState = aStartState;
+ maEndState = aEndState;
+ maElementName = aElementName;
+ msElementTypeName = sElementTypeName;
+ }
+
+
+
+
+ public State GetStartState ()
+ {
+ return maStartState;
+ }
+
+
+
+
+ public State GetEndState ()
+ {
+ return maEndState;
+ }
+
+
+
+
+ public QualifiedName GetElementName()
+ {
+ return maElementName;
+ }
+
+
+
+
+ public String GetElementTypeName()
+ {
+ return msElementTypeName;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("%s --'%s'-> %s (via %s)\n",
+ maStartState.GetFullname(),
+ maElementName.GetDisplayName(),
+ maEndState.GetFullname(),
+ msElementTypeName);
+ }
+
+
+
+
+ private final State maStartState;
+ private final State maEndState;
+ private final QualifiedName maElementName;
+ private final String msElementTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/ValidatingCreator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/ValidatingCreator.java
new file mode 100644
index 000000000000..c0dd5acf1781
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/ValidatingCreator.java
@@ -0,0 +1,793 @@
+/**************************************************************
+*
+* 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.Iterator;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.iterator.DereferencingNodeIterator;
+import org.apache.openoffice.ooxml.schema.iterator.PermutationIterator;
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexTypeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+/** Create a set of validating stack automatons for a set of schemas.
+ * There is one DFA (deterministic finite automaton) for each complex type and
+ * one for the top level elements.
+ */
+public class ValidatingCreator
+ extends CreatorBase
+ implements INodeVisitor
+{
+ public ValidatingCreator (
+ final SchemaBase aSchemaBase,
+ final File aLogFile)
+ {
+ super(aSchemaBase, aLogFile);
+ maContextStack = new Stack<>();
+ maCurrentContext = null;
+ }
+
+
+
+
+ /** Create one automaton for the top-level elements and one for each complex
+ * type.
+ */
+ public FiniteAutomatonContainer Create ()
+ {
+ final FiniteAutomatonContainer aAutomatons = new FiniteAutomatonContainer(maStateContainer);
+
+ // Create the automaton for the top-level elements.
+ aAutomatons.AddAutomaton(
+ null,
+ CreateForTopLevelElements());
+
+ // Create one automation 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 ()
+ {
+ maStateContext = new StateContext(
+ maStateContainer,
+ "<top-level>");
+ final State aEndState = maStateContext.CreateEndState();
+
+ assert(maContextStack.isEmpty());
+ msLogIndentation = "";
+
+ // top level elements
+ for (final Element aElement : maSchemaBase.TopLevelElements.GetSorted())
+ ProcessType(
+ aElement,
+ maStateContext.GetStartState(),
+ maStateContext.GetStartState(),
+ aEndState);
+
+ return new FiniteAutomaton(maStateContext, null, null);
+ }
+
+
+
+
+ private FiniteAutomaton CreateForComplexType (final ComplexType aComplexType)
+ {
+ maStateContext = new StateContext(
+ maStateContainer,
+ aComplexType.GetName().GetStateName());
+ maAttributes = new Vector<>();
+ final State aEndState = maStateContext.CreateEndState();
+ ProcessType(
+ aComplexType,
+ maStateContext.GetStartState(),
+ maStateContext.GetStartState(),
+ aEndState);
+ return new FiniteAutomaton(
+ maStateContext,
+ maAttributes,
+ aComplexType.GetLocation());
+ }
+
+
+
+
+ @Override
+ public void Visit (final All aAll)
+ {
+ maLog.AddComment("All");
+ ProcessAttributes(aAll);
+
+ // Make a transformation of the children into a choice of sequences that
+ // can then be processed by already existing Visit() methods.
+ // These sequences enumerate all permutations of the original children.
+ final INode aReplacement = GetAllReplacement(aAll);
+
+ final State aLocalStartState = maStateContext.CreateState(
+ maCurrentContext.BaseState,
+ "As");
+ final State aLocalEndState = maStateContext.CreateState(
+ maCurrentContext.BaseState,
+ "Ae");
+
+ maLog.StartBlock();
+ AddEpsilonTransition(maCurrentContext.StartState, aLocalStartState);
+ final long nStartTime = System.currentTimeMillis();
+ ProcessType(
+ aReplacement,
+ maStateContext.CreateState(maCurrentContext.BaseState, "A"),
+ aLocalStartState,
+ aLocalEndState);
+ final long nEndTime = System.currentTimeMillis();
+ System.out.printf("processed 'all' children in %fs\n", (nEndTime-nStartTime)/1000.0);
+ AddEpsilonTransition(aLocalEndState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final Any aAny)
+ {
+ assert(aAny.GetChildCount() == 0);
+
+ maLog.AddComment("Any");
+ ProcessAttributes(aAny);
+
+ AddSkipTransition(
+ maCurrentContext.StartState,
+ new SkipData(
+ aAny.GetProcessContentsFlag(),
+ aAny.GetNamespaces()));
+ AddEpsilonTransition(maCurrentContext.StartState, maCurrentContext.EndState);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexContent aComplexContent)
+ {
+ assert(aComplexContent.GetChildCount() == 1);
+
+ maLog.AddComment ("Complex Content.");
+ ProcessAttributes(aComplexContent);
+
+ maLog.StartBlock();
+ ProcessType(
+ aComplexContent.GetChildren().iterator().next(),
+ maCurrentContext.BaseState,
+ maCurrentContext.StartState,
+ maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexType aComplexType)
+ {
+ if (maLog != null)
+ {
+ maLog.printf("\n");
+ maLog.AddComment ("Complex Type %s defined in %s.",
+ aComplexType.GetName().GetDisplayName(),
+ aComplexType.GetLocation());
+ }
+ ProcessAttributes(aComplexType);
+
+ maLog.StartBlock();
+ maLog.printf("%sstarting at state %s\n", msLogIndentation, maCurrentContext.StartState.GetFullname());
+
+ if (GetElementCount(aComplexType) == 0)
+ {
+ // There are elements. Therefore there will be no transitions.
+ // The start state is accepting and the end state is not necessary.
+ maCurrentContext.StartState.SetIsAccepting();
+ maStateContext.RemoveState(maCurrentContext.EndState);
+ }
+
+ for (final INode aChild : aComplexType.GetChildren())
+ ProcessType(aChild, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexTypeReference aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final Choice aChoice)
+ {
+ maLog.AddComment("Choice");
+ ProcessAttributes(aChoice);
+
+ final State aLocalStartState = maStateContext.CreateState(maCurrentContext.BaseState, "Cs");
+ final State aLocalEndState = maStateContext.CreateState(maCurrentContext.BaseState, "Ce");
+ maLog.StartBlock();
+ AddEpsilonTransition(maCurrentContext.StartState, aLocalStartState);
+
+ int nStateIndex = 0;
+ for (final INode aChild : aChoice.GetChildren())
+ {
+ ProcessType(
+ aChild,
+ maStateContext.CreateState(maCurrentContext.BaseState, "C"+nStateIndex++),
+ aLocalStartState,
+ aLocalEndState);
+ }
+ AddEpsilonTransition(aLocalEndState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final Element aElement)
+ {
+ assert(aElement.GetChildCount()==0);
+
+ maLog.AddComment("Element: on '%s' go from %s to %s via %s",
+ aElement.GetElementName().GetDisplayName(),
+ maCurrentContext.StartState.GetFullname(),
+ maCurrentContext.EndState.GetFullname(),
+ aElement.GetTypeName().GetStateName());
+ ProcessAttributes(aElement);
+
+ final Transition aTransition = new Transition(
+ maCurrentContext.StartState,
+ maCurrentContext.EndState,
+ aElement.GetElementName(),
+ aElement.GetTypeName().GetStateName());
+ maCurrentContext.StartState.AddTransition(aTransition);
+
+ // 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);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ElementReference aReference)
+ {
+ assert(aReference.GetChildCount() == 0);
+
+ maLog.AddComment("Element reference to %s", aReference.GetReferencedElementName());
+ ProcessAttributes(aReference);
+
+ final Element aElement = aReference.GetReferencedElement(maSchemaBase);
+ if (aElement == null)
+ throw new RuntimeException("can't find referenced element "+aReference.GetReferencedElementName());
+ maLog.StartBlock();
+ ProcessType(aElement, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ /** Treat extension nodes like sequences (for now).
+ */
+ @Override
+ public void Visit (final Extension aExtension)
+ {
+ assert(aExtension.GetChildCount() <= 1);
+
+ maLog.AddComment("Extension of base type %s", aExtension.GetBaseTypeName());
+ ProcessAttributes(aExtension);
+
+ final Vector<INode> aNodes = aExtension.GetTypeNodes(maSchemaBase);
+
+ maLog.StartBlock();
+ int nStateIndex = 0;
+ State aCurrentState = maStateContext.CreateState(maCurrentContext.BaseState, "E"+nStateIndex++);
+ AddEpsilonTransition(maCurrentContext.StartState, aCurrentState);
+
+ State aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "E"+nStateIndex++);
+ ProcessType(aExtension.GetReferencedNode(maSchemaBase), aCurrentState, aCurrentState, aNextState);
+ aCurrentState = aNextState;
+
+ for (final INode aChild : aNodes)
+ {
+ aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "E"+nStateIndex++);
+ ProcessType(aChild, aCurrentState, aCurrentState, aNextState);
+ aCurrentState = aNextState;
+ }
+ AddEpsilonTransition(aCurrentState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final Group aGroup)
+ {
+ assert(aGroup.GetChildCount() == 1);
+
+ maLog.AddComment("Group %s", aGroup.GetName());
+ ProcessAttributes(aGroup);
+
+ maLog.StartBlock();
+ final State aGroupBaseState = maStateContext.CreateState(maCurrentContext.BaseState, "G");
+ ProcessType(
+ aGroup.GetOnlyChild(),
+ aGroupBaseState,
+ maCurrentContext.StartState,
+ maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final GroupReference aReference)
+ {
+ maLog.AddComment("Group reference to %s", aReference.GetReferencedGroupName());
+ ProcessAttributes(aReference);
+
+ final Group aGroup = aReference.GetReferencedGroup(maSchemaBase);
+ if (aGroup == null)
+ throw new RuntimeException("can't find referenced group "+aReference.GetReferencedGroupName());
+
+ maLog.StartBlock();
+ ProcessType(aGroup, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ /** An occurrence indicator defines how many times the single child can occur.
+ * The minimum value defines the mandatory number of times. The maximum value
+ * defines the optional number.
+ */
+ @Override
+ public void Visit (final OccurrenceIndicator aOccurrence)
+ {
+ assert(aOccurrence.GetChildCount() == 1);
+
+ maLog.AddComment("OccurrenceIndicator %s->%s",
+ aOccurrence.GetDisplayMinimum(),
+ aOccurrence.GetDisplayMaximum());
+ ProcessAttributes(aOccurrence);
+
+ maLog.StartBlock();
+
+ final INode aChild = aOccurrence.GetChildren().iterator().next();
+
+ int nIndex = 0;
+ State aCurrentState = maStateContext.CreateState(maCurrentContext.BaseState, "O"+nIndex++);
+ AddEpsilonTransition(maCurrentContext.StartState, aCurrentState);
+
+ if (aOccurrence.GetMinimum() == 0)
+ {
+ // A zero minimum means that all occurrences are optional.
+ // Add a short circuit from start to end.
+ maLog.AddComment("Occurrence: make whole element optional (min==0)");
+ AddEpsilonTransition(maCurrentContext.StartState, maCurrentContext.EndState);
+ }
+ else
+ {
+ // Write a row of mandatory transitions for the minimum.
+ for (; nIndex<=aOccurrence.GetMinimum(); ++nIndex)
+ {
+ // Add transition i-1 -> i (i == nIndex).
+ final State aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "O"+nIndex);
+ maLog.AddComment("Occurrence: move from %d -> %d (%s -> %s) (minimum)",
+ nIndex-1,
+ nIndex,
+ aCurrentState,
+ aNextState);
+ maLog.StartBlock();
+ ProcessType(aChild, aCurrentState, aCurrentState, aNextState);
+ maLog.EndBlock();
+ aCurrentState = aNextState;
+ }
+ }
+
+ if (aOccurrence.GetMaximum() == OccurrenceIndicator.unbounded)
+ {
+ // Write loop on last state when max is unbounded.
+
+ // last -> loop
+ final State aLoopState = maStateContext.CreateState(maCurrentContext.BaseState, "OL");
+ maLog.AddComment("Occurrence: forward to loop (maximum)");
+ AddEpsilonTransition(aCurrentState, aLoopState);
+
+ // loop -> loop
+ maLog.AddComment("Occurrence: loop");
+ maLog.StartBlock();
+ ProcessType(aChild, aLoopState, aLoopState, aLoopState);
+ maLog.EndBlock();
+
+ // -> end
+ maLog.AddComment("Occurrence: forward to local end");
+ AddEpsilonTransition(aLoopState, maCurrentContext.EndState);
+ }
+ else
+ {
+ // Write a row of optional transitions for the maximum.
+ for (; nIndex<=aOccurrence.GetMaximum(); ++nIndex)
+ {
+ if (nIndex > 0)
+ {
+ // i-1 -> end
+ maLog.AddComment("Occurrence: make %d optional (maximum)", nIndex-1);
+ AddEpsilonTransition(aCurrentState, maCurrentContext.EndState);
+ }
+
+ // i-1 -> i
+ final State aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "O"+nIndex);
+ maLog.AddComment("Occurrence: %d -> %d (%s -> %s) (maximum)",
+ nIndex-1,
+ nIndex,
+ aCurrentState,
+ aNextState);
+ maLog.StartBlock();
+ ProcessType(aChild, aCurrentState, aCurrentState, aNextState);
+ maLog.EndBlock();
+
+ aCurrentState = aNextState;
+ }
+
+ // max -> end
+ maLog.AddComment("Occurrence: forward to local end");
+ AddEpsilonTransition(aCurrentState, maCurrentContext.EndState);
+ }
+ maLog.EndBlock();
+ }
+
+
+
+
+ /** Ordered sequence of nodes.
+ * For n nodes create states S0 to Sn where Si and Si+1 become start and
+ * end states for the i-th child.
+ */
+ @Override
+ public void Visit (final Sequence aSequence)
+ {
+ maLog.AddComment("Sequence.");
+ ProcessAttributes(aSequence);
+
+ maLog.StartBlock();
+ int nStateIndex = 0;
+ State aCurrentState = maStateContext.CreateState(maCurrentContext.BaseState, "S"+nStateIndex++);
+ AddEpsilonTransition(maCurrentContext.StartState, aCurrentState);
+ for (final INode aChild : aSequence.GetChildren())
+ {
+ final State aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "S"+nStateIndex++);
+ ProcessType(aChild, aCurrentState, aCurrentState, aNextState);
+ aCurrentState = aNextState;
+ }
+ AddEpsilonTransition(aCurrentState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final BuiltIn aNode)
+ {
+ // Ignored.
+ //throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final List aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final Restriction aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+ @Override
+ public void Visit (final SimpleContent aNode)
+ {
+ maLog.AddComment("SimpleContent.");
+ ProcessAttributes(aNode);
+
+ for (final INode aChild : aNode.GetChildren())
+ ProcessType(aChild, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleType aNode)
+ {
+ maLog.AddComment("SimpleType.");
+ //for (final INode aChild : aNode.GetChildren())
+ //ProcessType(aChild, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleTypeReference aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final Union aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeGroup aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeReference aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final Attribute aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeGroupReference aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ private void ProcessType (
+ final INode aNode,
+ final State aBaseState,
+ final State aStartState,
+ final State aEndState)
+ {
+ maContextStack.push(maCurrentContext);
+ maCurrentContext = new Context(aBaseState, aStartState, aEndState);
+ aNode.AcceptVisitor(this);
+ maCurrentContext = maContextStack.pop();
+ }
+
+
+
+
+ private void AddEpsilonTransition (
+ final State aStartState,
+ final State aEndState)
+ {
+ // Silently ignore epsilon transitions from a state to itself.
+ // They may indicate a problem but usually are just artifacts
+ // that can be safely ignored.
+ if (aStartState == aEndState)
+ return;
+ else
+ {
+ final EpsilonTransition aTransition = new EpsilonTransition(
+ aStartState,
+ aEndState);
+ aStartState.AddEpsilonTransition(aTransition);
+
+ if (maLog != null)
+ {
+ maLog.printf("%sepsilon transition from %s to %s\n",
+ msLogIndentation,
+ aStartState.GetFullname(),
+ aEndState.GetFullname());
+ }
+ }
+ }
+
+
+
+
+ private int GetElementCount (final INode aNode)
+ {
+
+ class Visitor extends NodeVisitorAdapter
+ {
+ int nElementCount = 0;
+ @Override public void Visit (final Element aElement)
+ {
+ ++nElementCount;
+ }
+ int GetElementCount ()
+ {
+ return nElementCount;
+ }
+ };
+ final Visitor aVisitor = new Visitor();
+ for (final INode aChildNode : new DereferencingNodeIterator(aNode, maSchemaBase, false))
+ {
+ aChildNode.AcceptVisitor(aVisitor);
+ }
+ return aVisitor.GetElementCount();
+ }
+
+
+
+
+ private INode GetAllReplacement (final All aAll)
+ {
+ final long nStartTime = System.currentTimeMillis();
+
+ // By default each child of this node can appear exactly once, however
+ // the order is undefined. This corresponds to an enumeration of all
+ // permutations of the children.
+
+ // Set up an array of all children. This array will be modified to contain
+ // all permutations.
+ final INode[] aNodes = new INode[aAll.GetChildCount()];
+ final Iterator<INode> aChildren = aAll.GetChildren().iterator();
+ for (int nIndex=0; aChildren.hasNext(); ++nIndex)
+ aNodes[nIndex] = aChildren.next();
+
+ final Location aLocation = aAll.GetLocation();
+ final Choice aChoice = new Choice(aAll, aLocation);
+
+ // Treat every permutation as sequence so that the whole set of permutations
+ // is equivalent to a choice of sequences.
+ int nCount = 0;
+ for (final PermutationIterator<INode> aIterator = new PermutationIterator<>(aNodes); aIterator.HasMore(); aIterator.Next())
+ {
+ // Create a Sequence node for the current permutation and add it as
+ // choice to the Choice node.
+ final Sequence aSequence = new Sequence(aChoice, null, aLocation);
+ aChoice.AddChild(aSequence);
+
+ for (final INode aNode : aNodes)
+ aSequence.AddChild(aNode);
+
+ ++nCount;
+ }
+ final long nEndTime = System.currentTimeMillis();
+ System.out.printf("created %d permutations in %fs\n",
+ nCount,
+ (nEndTime-nStartTime)/1000.0);
+
+ return aChoice;
+ }
+
+
+
+
+ class Context
+ {
+ Context (
+ final State aBaseState,
+ final State aStartState,
+ final State aEndState)
+ {
+ BaseState = aBaseState;
+ StartState = aStartState;
+ EndState = aEndState;
+ }
+ final State BaseState;
+ final State StartState;
+ final State EndState;
+ }
+
+
+
+
+ private StateContext maStateContext;
+ private final Stack<Context> maContextStack;
+ private Context maCurrentContext;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/LogGenerator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/LogGenerator.java
new file mode 100644
index 000000000000..36deab269b96
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/LogGenerator.java
@@ -0,0 +1,313 @@
+/**************************************************************
+*
+* 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.generator;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.util.Map.Entry;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+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;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+
+public class LogGenerator
+{
+ public static void Write (
+ final File aOutputFile,
+ final SchemaBase aSchemaBase,
+ final Iterable<Schema> aTopLevelSchemas)
+ {
+ final long nStartTime = System.currentTimeMillis();
+
+ try
+ {
+ final LogGenerator aGenerator = new LogGenerator(
+ new PrintStream(aOutputFile),
+ aSchemaBase);
+
+ aGenerator.WriteNamespaces(aSchemaBase);
+ aGenerator.WriteTopLevelElements(aTopLevelSchemas);
+ aGenerator.WriteComplexTypes(aSchemaBase);
+ aGenerator.WriteGroups(aSchemaBase);
+ aGenerator.WriteSimpleTypes(aSchemaBase);
+ aGenerator.WriteAttributeGroups(aSchemaBase);
+ aGenerator.WriteAttributes(aSchemaBase);
+ }
+ catch (final FileNotFoundException aException)
+ {
+ aException.printStackTrace();
+ }
+
+ final long nEndTime = System.currentTimeMillis();
+ System.out.printf("wrote log output to '%s' in %fs\n",
+ aOutputFile.toString(),
+ (nEndTime-nStartTime)/1000.0f);
+ }
+
+
+
+
+ private LogGenerator (
+ final PrintStream aOut,
+ final SchemaBase aSchemaBase)
+ {
+ maSchemaBase = aSchemaBase;
+ maOut = aOut;
+ }
+
+
+
+
+ private void WriteComment (final String sFormat, final Object ... aArgumentList)
+ {
+ maOut.printf("// "+sFormat+"\n", aArgumentList);
+ }
+
+
+
+
+ private void WriteNamespaces (final SchemaBase aSchema)
+ {
+ // Write namespace definitions.
+ WriteComment("%d Namespaces.", aSchema.Namespaces.GetCount());
+ for (final Entry<String,String> aEntry : aSchema.Namespaces.GetSorted())
+ {
+ maOut.printf(" %s -> %s\n",
+ aEntry.getValue()==null ? "<no-prefix>" : aEntry.getValue(),
+ aEntry.getKey());
+ }
+ }
+
+
+
+ private void WriteTopLevelElements (final Iterable<Schema> aTopLevelSchemas)
+ {
+ // Write top level elements.
+ WriteComment("Top-level elements.");
+ for (final Schema aSchema : aTopLevelSchemas)
+ {
+ WriteComment(" Schema %s.", aSchema.GetShortName());
+ for (final Element aElement : aSchema.TopLevelElements.GetSorted())
+ maOut.printf(" \"%s\" -> %s\n",
+ aElement.GetElementName().GetDisplayName(),
+ aElement.GetTypeName().GetDisplayName());
+ }
+ }
+
+
+
+
+ private void WriteComplexTypes (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Complex Types.", aSchema.ComplexTypes.GetCount());
+ for (final ComplexType aType : aSchema.ComplexTypes.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteSimpleTypes (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Simple Types.", aSchema.SimpleTypes.GetCount());
+ for (final SimpleType aType : aSchema.SimpleTypes.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteGroups (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Groups.", aSchema.Groups.GetCount());
+ for (final Node aType : aSchema.Groups.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteAttributeGroups (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Attribute Groups.", aSchema.AttributeGroups.GetCount());
+ for (final Node aType : aSchema.AttributeGroups.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteAttributes (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Attributes.", aSchema.Attributes.GetCount());
+ for (final Node aType : aSchema.Attributes.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteType (
+ final String sIndentation,
+ final INode aType,
+ final boolean bIsTopLevel)
+ {
+ maOut.printf("%s%s", sIndentation, aType.toString());
+
+ if (bIsTopLevel)
+ {
+ final Node aNode = (Node)aType;
+ maOut.printf(" defined at %s",
+ aNode.GetLocation());
+ }
+ if ( ! HasChild(aType))
+ {
+ maOut.printf(" {}\n");
+ }
+ else
+ {
+ maOut.printf(" {\n");
+
+ // Write attributes.
+ switch(aType.GetNodeType())
+ {
+ case ComplexType:
+ for (final INode aAttribute : ((ComplexType)aType).GetAttributes())
+ WriteAttribute(sIndentation+" ", aAttribute);
+ break;
+
+ case SimpleTypeReference:
+ WriteType(
+ sIndentation+" ",
+ ((SimpleTypeReference)aType).GetReferencedSimpleType(maSchemaBase),
+ false);
+ break;
+
+ default:
+ break;
+ }
+
+
+ // Write child types.
+ for (final INode aChild : aType.GetChildren())
+ WriteType(sIndentation+" ", aChild, false);
+
+ maOut.printf("%s}\n", sIndentation);
+ }
+ }
+
+
+
+
+ private void WriteAttribute (
+ final String sIndentation,
+ final INode aAttribute)
+ {
+ switch(aAttribute.GetNodeType())
+ {
+ case Attribute:
+ maOut.printf(
+ "%sattribute %s of type %s\n",
+ sIndentation,
+ ((Attribute)aAttribute).GetName().GetDisplayName(),
+ ((Attribute)aAttribute).GetTypeName().GetDisplayName());
+ break;
+
+ case AttributeGroup:
+ maOut.printf(
+ "%sattribute group %s {\n",
+ sIndentation,
+ ((AttributeGroup)aAttribute).GetName().GetDisplayName());
+ for (final INode aChildAttribute : ((AttributeGroup)aAttribute).GetChildren())
+ WriteAttribute(sIndentation+" ", aChildAttribute);
+ maOut.printf("%s}\n", sIndentation);
+ break;
+ case AttributeGroupReference:
+ maOut.printf(
+ "%sreference to attribute group %s {\n",
+ sIndentation,
+ ((AttributeGroupReference)aAttribute).GetReferencedName().GetDisplayName());
+ WriteAttribute(sIndentation+" ", ((AttributeGroupReference)aAttribute).GetReferencedAttributeGroup(maSchemaBase));
+ maOut.printf("%s}\n", sIndentation);
+ break;
+
+ case AttributeReference:
+ maOut.printf(
+ "%sreference to attribute %s {\n",
+ sIndentation,
+ ((AttributeReference)aAttribute).GetReferencedName().GetDisplayName());
+ WriteAttribute(sIndentation+" ", ((AttributeReference)aAttribute).GetReferencedAttribute(maSchemaBase));
+ maOut.printf("%s}\n", sIndentation);
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ private boolean HasChild (final INode aType)
+ {
+ if (aType.GetChildren().iterator().hasNext())
+ return true;
+
+ switch (aType.GetNodeType())
+ {
+ case ComplexType:
+ return ((ComplexType)aType).GetAttributes().iterator().hasNext();
+
+ case SimpleTypeReference:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+
+
+
+ private final SchemaBase maSchemaBase;
+ private final PrintStream maOut;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/ParserTablesGenerator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/ParserTablesGenerator.java
new file mode 100644
index 000000000000..99cfbe1161bb
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/ParserTablesGenerator.java
@@ -0,0 +1,555 @@
+/**************************************************************
+*
+* 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.generator;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.automaton.FiniteAutomaton;
+import org.apache.openoffice.ooxml.schema.automaton.FiniteAutomatonContainer;
+import org.apache.openoffice.ooxml.schema.automaton.SkipData;
+import org.apache.openoffice.ooxml.schema.automaton.State;
+import org.apache.openoffice.ooxml.schema.automaton.Transition;
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeBase.Use;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.NamespaceMap;
+import org.apache.openoffice.ooxml.schema.parser.FormDefault;
+import org.apache.openoffice.ooxml.schema.simple.BlobNode;
+import org.apache.openoffice.ooxml.schema.simple.DateTimeNode;
+import org.apache.openoffice.ooxml.schema.simple.ISimpleTypeNode;
+import org.apache.openoffice.ooxml.schema.simple.ISimpleTypeNodeVisitor;
+import org.apache.openoffice.ooxml.schema.simple.NumberNode;
+import org.apache.openoffice.ooxml.schema.simple.SimpleTypeContainer;
+import org.apache.openoffice.ooxml.schema.simple.SimpleTypeDescriptor;
+import org.apache.openoffice.ooxml.schema.simple.StringNode;
+import org.apache.openoffice.ooxml.schema.simple.UnionNode;
+
+public class ParserTablesGenerator
+{
+ public ParserTablesGenerator (
+ final FiniteAutomatonContainer aAutomatons,
+ final NamespaceMap aNamespaces,
+ final SimpleTypeContainer aSimpleTypes,
+ final Map<String,Integer> aAttributeValueToIdMap)
+ {
+ maAutomatons = aAutomatons;
+ maSimpleTypes = aSimpleTypes;
+ maNamespaces = aNamespaces;
+ maNameToIdMap = new TreeMap<>();
+ maPrefixToIdMap = new HashMap<>();
+ maTypeNameToIdMap = new TreeMap<>();
+ maAttributeValueToIdMap = aAttributeValueToIdMap;
+ }
+
+
+
+
+ public void Generate (
+ final File aParseTableFile)
+ {
+ final long nStartTime = System.currentTimeMillis();
+
+ SetupNameList();
+ AssignNameIds();
+
+ try
+ {
+ final PrintStream aOut = new PrintStream(new FileOutputStream(aParseTableFile));
+
+ WriteNamespaceList(aOut);
+ WriteNameList(aOut);
+ WriteGlobalStartEndStates(aOut);
+ WriteAutomatonList(aOut);
+ WriteSimpleTypes(aOut);
+ WriteAttributeValues(aOut);
+ aOut.close();
+ }
+ catch (final FileNotFoundException aException)
+ {
+ aException.printStackTrace();
+ }
+
+ final long nEndTime = System.currentTimeMillis();
+ System.out.printf("wrote parse tables to %s in %fs\n",
+ aParseTableFile.toString(),
+ (nEndTime-nStartTime)/1000.0);
+ }
+
+
+
+
+ private void SetupNameList ()
+ {
+ final Set<String> aNames = new TreeSet<>();
+
+ // Add the element names.
+ for (final FiniteAutomaton aAutomaton : maAutomatons.GetAutomatons())
+ for (final Transition aTransition : aAutomaton.GetTransitions())
+ {
+ if (aTransition.GetElementName() == null)
+ throw new RuntimeException();
+ aNames.add(aTransition.GetElementName().GetLocalPart());
+ }
+
+ // Add the attribute names.
+ for (final FiniteAutomaton aAutomaton : maAutomatons.GetAutomatons())
+ for (final Attribute aAttribute : aAutomaton.GetAttributes())
+ aNames.add(aAttribute.GetName().GetLocalPart());
+
+ // Create unique ids for the names.
+ int nIndex = 1;
+ maNameToIdMap.clear();
+ for (final String sName : aNames)
+ maNameToIdMap.put(sName, nIndex++);
+
+ // Create unique ids for namespace prefixes.
+ nIndex = 1;
+ maPrefixToIdMap.clear();
+ for (final Entry<String, String> aEntry : maNamespaces)
+ {
+ maPrefixToIdMap.put(aEntry.getValue(), nIndex++);
+ }
+ }
+
+
+
+
+ /** During the largest part of the parsing process, states and elements are
+ * identified not via their name but via a unique id.
+ * That allows a fast lookup.
+ */
+ private void AssignNameIds ()
+ {
+ maTypeNameToIdMap.clear();
+ int nIndex = 0;
+
+ // Process state names.
+ final Set<QualifiedName> aSortedTypeNames = new TreeSet<>();
+ for (final State aState : maAutomatons.GetStates())
+ aSortedTypeNames.add(aState.GetQualifiedName());
+ for (final Entry<String, SimpleTypeDescriptor> aSimpleType : maSimpleTypes.GetSimpleTypes())
+ aSortedTypeNames.add(aSimpleType.getValue().GetName());
+
+ for (final QualifiedName aName : aSortedTypeNames)
+ maTypeNameToIdMap.put(aName.GetStateName(), nIndex++);
+ }
+
+
+
+
+ private void WriteNamespaceList (final PrintStream aOut)
+ {
+ aOut.printf("# namespaces\n");
+ for (final Entry<String, String> aEntry : maNamespaces)
+ {
+ aOut.printf("namespace %-8s %2d %s\n",
+ aEntry.getValue(),
+ maPrefixToIdMap.get(aEntry.getValue()),
+ aEntry.getKey());
+ }
+ }
+
+
+
+
+ private void WriteGlobalStartEndStates (final PrintStream aOut)
+ {
+ aOut.printf("\n# start and end states\n");
+
+ final FiniteAutomaton aAutomaton = maAutomatons.GetTopLevelAutomaton();
+ final State aStartState = aAutomaton.GetStartState();
+ aOut.printf("start-state %4d %s\n",
+ maTypeNameToIdMap.get(aStartState.GetFullname()),
+ aStartState.GetFullname());
+ for (final State aAcceptingState : aAutomaton.GetAcceptingStates())
+ aOut.printf("end-state %4d %s\n",
+ maTypeNameToIdMap.get(aAcceptingState.GetFullname()),
+ aAcceptingState.GetFullname());
+ }
+
+
+
+
+ private void WriteNameList (final PrintStream aOut)
+ {
+ aOut.printf("\n# %d names\n", maNameToIdMap.size());
+ for (final Entry<String, Integer> aEntry : maNameToIdMap.entrySet())
+ {
+ aOut.printf("name %4d %s\n",
+ aEntry.getValue(),
+ aEntry.getKey());
+ }
+
+ aOut.printf("\n# %s states\n", maTypeNameToIdMap.size());
+ for (final Entry<String, Integer> aEntry : maTypeNameToIdMap.entrySet())
+ {
+ aOut.printf("state-name %4d %s\n",
+ aEntry.getValue(),
+ aEntry.getKey());
+ }
+ }
+
+
+
+
+ private void WriteAutomatonList (final PrintStream aOut)
+ {
+ for (final FiniteAutomaton aAutomaton : maAutomatons.GetAutomatons())
+ {
+ aOut.printf("# %s at %s\n", aAutomaton.GetTypeName(), aAutomaton.GetLocation());
+
+ final State aStartState = aAutomaton.GetStartState();
+ final int nStartStateId = maTypeNameToIdMap.get(aStartState.GetFullname());
+
+ // Write start state.
+ aOut.printf("start-state %d %s\n",
+ nStartStateId,
+ aStartState);
+
+ // Write accepting states.
+ for (final State aState : aAutomaton.GetAcceptingStates())
+ {
+ aOut.printf("accepting-state %d %s\n",
+ maTypeNameToIdMap.get(aState.GetFullname()),
+ aState.GetFullname());
+ }
+
+ // Write text type.
+ final INode aTextType = aStartState.GetTextType();
+ if (aTextType != null)
+ {
+ switch(aTextType.GetNodeType())
+ {
+ case BuiltIn:
+ aOut.printf("text-type %d %d %s\n",
+ nStartStateId,
+ maTypeNameToIdMap.get(aTextType.GetName().GetStateName()),
+ aTextType.GetName().GetStateName());
+ break;
+ case SimpleType:
+ aOut.printf("text-type %d %d %s\n",
+ nStartStateId,
+ maTypeNameToIdMap.get(aTextType.GetName().GetStateName()),
+ aTextType.GetName().GetStateName());
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ WriteAttributes(
+ aOut,
+ aStartState,
+ aAutomaton.GetAttributes());
+
+ // Write transitions.
+ for (final Transition aTransition : aAutomaton.GetTransitions())
+ {
+ final Integer nId = maTypeNameToIdMap.get(aTransition.GetElementTypeName());
+ aOut.printf("transition %4d %4d %2d %4d %4d %s %s %s %s\n",
+ maTypeNameToIdMap.get(aTransition.GetStartState().GetFullname()),
+ maTypeNameToIdMap.get(aTransition.GetEndState().GetFullname()),
+ maPrefixToIdMap.get(aTransition.GetElementName().GetNamespacePrefix()),
+ maNameToIdMap.get(aTransition.GetElementName().GetLocalPart()),
+ nId!=null ? nId : -1,
+ aTransition.GetStartState().GetFullname(),
+ aTransition.GetEndState().GetFullname(),
+ aTransition.GetElementName().GetStateName(),
+ aTransition.GetElementTypeName());
+ }
+ // Write skip data.
+ for (final State aState : aAutomaton.GetStates())
+ {
+ for (@SuppressWarnings("unused") final SkipData aSkipData : aState.GetSkipData())
+ aOut.printf("skip %4d %s\n",
+ maTypeNameToIdMap.get(aState.GetFullname()),
+ aState.GetFullname());
+ }
+ }
+ }
+
+
+
+
+ private void WriteAttributes (
+ final PrintStream aOut,
+ final State aState,
+ final Iterable<Attribute> aAttributes)
+ {
+ // Write attributes.
+ for (final Attribute aAttribute : aAttributes)
+ {
+ aOut.printf("attribute %4d %2d %c %4d %4d %s %s %s %s %s\n",
+ maTypeNameToIdMap.get(aState.GetFullname()),
+ maPrefixToIdMap.get(aAttribute.GetName().GetNamespacePrefix()),
+ aAttribute.GetFormDefault()==FormDefault.qualified ? 'q' : 'u',
+ maNameToIdMap.get(aAttribute.GetName().GetLocalPart()),
+ maTypeNameToIdMap.get(aAttribute.GetTypeName().GetStateName()),
+ aAttribute.GetUse()==Use.Optional ? 'o' : 'u',
+ aAttribute.GetDefault()==null ? "null" : '"'+aAttribute.GetDefault()+'"',
+ aState.GetFullname(),
+ aAttribute.GetName().GetStateName(),
+ aAttribute.GetTypeName().GetStateName());
+ }
+ }
+
+
+
+
+ private void WriteSimpleTypes (
+ final PrintStream aOut)
+ {
+ if (maSimpleTypes == null)
+ {
+ aOut.printf("\n// There is no simple type information.\n");
+ }
+ else
+ {
+ aOut.printf("\n// %d simple types.\n", maSimpleTypes.GetSimpleTypeCount());
+ for (final Entry<String,SimpleTypeDescriptor> aEntry : maSimpleTypes.GetSimpleTypesSorted())
+ {
+ int nIndex = 0;
+ for (final ISimpleTypeNode aSubType : aEntry.getValue().GetSubType())
+ {
+ final int nCurrentIndex = nIndex++;
+
+ final StringBuffer aLine = new StringBuffer();
+ aLine.append(String.format(
+ "simple-type %5d %1d %c ",
+ maTypeNameToIdMap.get(aEntry.getKey()),
+ nCurrentIndex,
+ aSubType.IsList() ? 'L' : 'T'));
+
+ aSubType.AcceptVisitor(new ISimpleTypeNodeVisitor()
+ {
+ @Override public void Visit(UnionNode aType)
+ {
+ throw new RuntimeException("unexpected");
+ }
+ @Override public void Visit(StringNode aType)
+ {
+ AppendStringDescription(aLine, aType);
+ }
+ @Override public void Visit(NumberNode<?> aType)
+ {
+ AppendNumberDescription(aLine, aType);
+ }
+ @Override public void Visit(DateTimeNode aType)
+ {
+ AppendDateTimeDescription(aLine, aType);
+ }
+ @Override public void Visit(BlobNode aType)
+ {
+ AppendBlobDescription(aLine, aType);
+ }
+ });
+ aOut.printf("%s\n", aLine.toString());
+ }
+ }
+ }
+ }
+
+
+
+
+ private void WriteAttributeValues (
+ final PrintStream aOut)
+ {
+ final Map<String,Integer> aSortedMap = new TreeMap<>();
+ aSortedMap.putAll(maAttributeValueToIdMap);
+ aOut.printf("// %d attribute values from enumerations.\n", maAttributeValueToIdMap.size());
+ for (final Entry<String,Integer> aEntry : aSortedMap.entrySet())
+ aOut.printf("attribute-value %5d %s\n", aEntry.getValue(), QuoteString(aEntry.getKey()));
+ }
+
+
+
+
+ private static void AppendStringDescription (
+ final StringBuffer aLine,
+ final StringNode aType)
+ {
+ aLine.append("S ");
+ switch(aType.GetRestrictionType())
+ {
+ case Enumeration:
+ aLine.append('E');
+ for (final int nValueId : aType.GetEnumerationRestriction())
+ {
+ aLine.append(' ');
+ aLine.append(nValueId);
+ }
+ break;
+ case Pattern:
+ aLine.append("P ");
+ aLine.append(QuoteString(aType.GetPatternRestriction()));
+ break;
+ case Length:
+ aLine.append("L ");
+ final int[] aLengthRestriction = aType.GetLengthRestriction();
+ aLine.append(aLengthRestriction[0]);
+ aLine.append(' ');
+ aLine.append(aLengthRestriction[1]);
+ break;
+ case None:
+ aLine.append('N');
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ private static void AppendNumberDescription (
+ final StringBuffer aLine,
+ final NumberNode<?> aType)
+ {
+ aLine.append("N ");
+ switch(aType.GetNumberType())
+ {
+ case Boolean: aLine.append("u1"); break;
+ case Byte: aLine.append("s8"); break;
+ case UnsignedByte: aLine.append("u8"); break;
+ case Short: aLine.append("s16"); break;
+ case UnsignedShort: aLine.append("u16"); break;
+ case Int: aLine.append("s32"); break;
+ case UnsignedInt: aLine.append("u32"); break;
+ case Long: aLine.append("s64"); break;
+ case UnsignedLong: aLine.append("u64"); break;
+ case Integer: aLine.append("s*"); break;
+ case Float: aLine.append("f"); break;
+ case Double: aLine.append("d"); break;
+ default:
+ throw new RuntimeException("unsupported numerical type "+aType.GetNumberType());
+ }
+ aLine.append(' ');
+ switch(aType.GetRestrictionType())
+ {
+ case Enumeration:
+ aLine.append("E ");
+ for (final Object nValue : aType.GetEnumerationRestriction())
+ {
+ aLine.append(" ");
+ aLine.append(nValue);
+ }
+ break;
+ case Size:
+ aLine.append("S");
+ if (aType.GetMinimum() != null)
+ {
+ if (aType.IsMinimumInclusive())
+ aLine.append(" >= ");
+ else
+ aLine.append(" > ");
+ aLine.append(aType.GetMinimum());
+ }
+ if (aType.GetMaximum() != null)
+ {
+ if (aType.IsMaximumInclusive())
+ aLine.append(" <= ");
+ else
+ aLine.append(" < ");
+ aLine.append(aType.GetMaximum());
+ }
+ break;
+ case None:
+ aLine.append("N");
+ break;
+ default:
+ throw new RuntimeException("unsupported numerical restriction "+aType.GetRestrictionType());
+ }
+ }
+
+
+
+
+ private static void AppendDateTimeDescription (
+ final StringBuffer aLine,
+ final DateTimeNode aType)
+ {
+ aLine.append("D");
+ }
+
+
+
+
+ private static void AppendBlobDescription (
+ final StringBuffer aLine,
+ final BlobNode aType)
+ {
+ aLine.append("B ");
+ switch(aType.GetBlobType())
+ {
+ case Base64Binary:
+ aLine.append("B ");
+ break;
+ case HexBinary:
+ aLine.append ("H ");
+ break;
+ default:
+ throw new RuntimeException("unsupported blob type");
+ }
+ switch(aType.GetRestrictionType())
+ {
+ case Length:
+ aLine.append("L ");
+ aLine.append(aType.GetLengthRestriction());
+ break;
+ case None:
+ aLine.append("N");
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ private static String QuoteString(final String sText)
+ {
+ return "\"" + sText.replace("\"", "&quot;").replace(" ", "%20") + "\"";
+ }
+
+
+
+
+ private final FiniteAutomatonContainer maAutomatons;
+ private final SimpleTypeContainer maSimpleTypes;
+ private final NamespaceMap maNamespaces;
+ private final Map<String,Integer> maNameToIdMap;
+ private final Map<String,Integer> maPrefixToIdMap;
+ private final Map<String,Integer> maTypeNameToIdMap;
+ private final Map<String,Integer> maAttributeValueToIdMap;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/HtmlGenerator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/HtmlGenerator.java
new file mode 100644
index 000000000000..189554766ada
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/HtmlGenerator.java
@@ -0,0 +1,623 @@
+/**************************************************************
+*
+* 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.generator.html;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexTypeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.schema.Schema;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+/** Create a single HTML page that shows information about all
+ * complex and simple types.
+ */
+public class HtmlGenerator
+ implements INodeVisitor
+{
+ public HtmlGenerator(
+ final SchemaBase aSchemaBase,
+ final Map<String, Schema> aTopLevelSchemas,
+ final File aOutputFile)
+ {
+ maSchemaBase = aSchemaBase;
+ maTopLevelSchemas = aTopLevelSchemas;
+ msIndentation = "";
+ msSingleIndentation = " ";
+ msSpace = " ";
+ try
+ {
+ maOut = new PrintStream(new FileOutputStream(aOutputFile));
+ } catch (FileNotFoundException aException)
+ {
+ aException.printStackTrace();
+ throw new RuntimeException(aException);
+ }
+ }
+
+
+
+
+ /** Read a template HTML file, expand its $... references and write the resulting content.
+ */
+ public void Generate ()
+ {
+ CopyFile("linking-template.html", true);
+ maOut.close();
+ }
+
+
+
+
+ private void CopyFile (
+ final String sBasename,
+ final boolean bIsTemplate)
+ {
+ try
+ {
+ final BufferedReader aIn = new BufferedReader(
+ new InputStreamReader(
+ new FileInputStream(
+ new File(
+ new File("bin/org/apache/openoffice/ooxml/schema/generator/html"),
+ sBasename))));
+
+ final Pattern aReferencePattern = Pattern.compile("^(.*?)\\$([^\\$]+)\\$(.*)$");
+ while (true)
+ {
+ final String sLine = aIn.readLine();
+ if (sLine == null)
+ break;
+
+ if (bIsTemplate)
+ {
+ final Matcher aMatcher = aReferencePattern.matcher(sLine);
+ if (aMatcher.matches())
+ {
+ maOut.println(aMatcher.group(1));
+ switch(aMatcher.group(2))
+ {
+ case "CSS":
+ CopyFile("display.css", false);
+ break;
+ case "CODE":
+ CopyFile("code.js", false);
+ break;
+ case "DATA":
+ WriteJsonData();
+ break;
+ }
+ maOut.printf("%s\n", aMatcher.group(3));
+ }
+ else
+ maOut.printf("%s\n", sLine);
+ }
+ else
+ maOut.printf("%s\n", sLine);
+ }
+ aIn.close();
+ }
+ catch (final Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+
+
+
+ private void WriteJsonData ()
+ {
+ maOut.printf("Data={\n");
+
+ WriteTopLevelNodes(maSchemaBase.ComplexTypes.GetSorted());
+ WriteTopLevelNodes(maSchemaBase.SimpleTypes.GetSorted());
+ WriteTopLevelNodes(maSchemaBase.Groups.GetSorted());
+ WriteTopLevelNodes(maSchemaBase.AttributeGroups.GetSorted());
+
+ maOut.printf("}\n");
+ }
+
+
+
+
+ private void WriteTopLevelNodes (final Iterable<? extends INode> aNodes)
+ {
+ for (final INode aNode : aNodes)
+ {
+ maOut.printf(" \"%s\" : {\n", aNode.GetName().GetDisplayName());
+
+ final String sSavedIndentation = msIndentation;
+ msIndentation += msSingleIndentation + msSingleIndentation;
+ aNode.AcceptVisitor(this);
+ msIndentation = sSavedIndentation;
+
+ maOut.printf(" }, \n");
+ }
+ }
+
+
+
+
+ @Override
+ public void Visit (final All aNode)
+ {
+ WritePair("type", "all");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Any aNode)
+ {
+ WritePair("type", "any");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexContent aNode)
+ {
+ WritePair("type", "complex-content");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexType aNode)
+ {
+ WritePair("type", "complex-type");
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexTypeReference aReference)
+ {
+ WritePair("type", "complex-type-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-complex-type", aReference.GetReferencedTypeName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Choice aNode)
+ {
+ WritePair("type", "choice");
+ WriteLocation(aNode);
+ WriteChildren(aNode);
+ WriteAttributes(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Element aNode)
+ {
+ WritePair("type", "element");
+ WriteLocation(aNode);
+ WritePair("tag", aNode.GetElementName().GetDisplayName());
+ WritePair("result-type", aNode.GetTypeName().GetDisplayName());
+ WriteAttributes(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ElementReference aReference)
+ {
+ WritePair("type", "element-type-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-element", aReference.GetReferencedElementName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Extension aNode)
+ {
+ WritePair("type", "extension");
+ WriteLocation(aNode);
+ WritePair("base-type", aNode.GetBaseTypeName().GetDisplayName());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Group aNode)
+ {
+ WritePair("type", "group");
+ WriteLocation(aNode);
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final GroupReference aReference)
+ {
+ WritePair("type", "group-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-group", aReference.GetReferencedGroupName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final OccurrenceIndicator aNode)
+ {
+ WritePair("type", "occurrence");
+ WriteLocation(aNode);
+ WritePair("minimum", aNode.GetDisplayMinimum());
+ WritePair("maximum", aNode.GetDisplayMaximum());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Sequence aNode)
+ {
+ WritePair("type", "sequence");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final BuiltIn aNode)
+ {
+ WritePair("type", "builtin");
+ WriteLocation(aNode);
+ WritePair("builtin-type", aNode.GetBuiltInType().GetQualifiedName().GetDisplayName());
+ WriteAttributes(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final List aNode)
+ {
+ WritePair("type", "list");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Restriction aNode)
+ {
+ WritePair("type", "restriction");
+ WriteLocation(aNode);
+ WritePair("base-type", aNode.GetBaseType().GetDisplayName());
+ WriteAttributes(aNode);
+
+ if (aNode.HasFeature(Restriction.EnumerationBit))
+ WritePair("enumeration", Join(aNode.GetEnumeration(), ";"));
+ if (aNode.HasFeature(Restriction.PatternBit))
+ WritePair("pattern", QuoteString(aNode.GetPattern()));
+ if (aNode.HasFeature(Restriction.MinExclusiveBit))
+ WritePair("exclusive-minimum", aNode.GetMinExclusive());
+ if (aNode.HasFeature(Restriction.MinInclusiveBit))
+ WritePair("inclusive-minimum", aNode.GetMinInclusive());
+ if (aNode.HasFeature(Restriction.MaxInclusiveBit))
+ WritePair("inclusive-maximum", aNode.GetMaxInclusive());
+ if (aNode.HasFeature(Restriction.MaxInclusiveBit))
+ WritePair("inclusive-maximum", aNode.GetMaxInclusive());
+ if (aNode.HasFeature(Restriction.LengthBit))
+ WritePair("length", Integer.toString(aNode.GetLength()));
+ if (aNode.HasFeature(Restriction.MinLengthBit))
+ WritePair("minimum-length", Integer.toString(aNode.GetMinimumLength()));
+ if (aNode.HasFeature(Restriction.MaxLengthBit))
+ WritePair("maximum-length", Integer.toString(aNode.GetMaximumLength()));
+ assert(aNode.GetChildCount() == 0);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleContent aNode)
+ {
+ WritePair("type", "simple-content");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleType aNode)
+ {
+ WritePair("type", "simple-type");
+ WriteLocation(aNode);
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleTypeReference aReference)
+ {
+ WritePair("type", "simple-type-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-simple-type", aReference.GetReferencedTypeName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Union aNode)
+ {
+ WritePair("type", "union");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeGroup aNode)
+ {
+ WritePair("type", "attribute-group");
+ WriteLocation(aNode);
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeReference aReference)
+ {
+ WritePair("type", "attribute-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-attribute", aReference.GetReferencedName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Attribute aNode)
+ {
+ WritePair("type", "attribute");
+ WriteLocation(aNode);
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WritePair("default-value", aNode.GetDefault());
+ WritePair("value-type", aNode.GetTypeName().GetDisplayName());
+ WritePair("use", aNode.GetUse().toString());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeGroupReference aReference)
+ {
+ WritePair("type", "attribute-group-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-attribute-group", aReference.GetReferencedName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ private void WriteChildren (
+ final INode aParent)
+ {
+ if (aParent.GetChildCount() > 0)
+ {
+ maOut.printf("%s\"children\" : [\n", msIndentation);
+ int nIndex = 0;
+ for (final INode aChild : aParent.GetChildren())
+ {
+ maOut.printf("%s%s{\n", msIndentation, msSingleIndentation, nIndex++);
+
+ final String sSavedIndentation = msIndentation;
+ msIndentation += msSingleIndentation + msSingleIndentation;
+ aChild.AcceptVisitor(this);
+ msIndentation = sSavedIndentation;
+
+ maOut.printf("%s%s},\n", msIndentation, msSingleIndentation);
+ }
+
+ maOut.printf("%s]\n", msIndentation);
+ }
+ }
+
+
+
+
+ private void WriteAttributes (
+ final INode aParent)
+ {
+ if (aParent.GetAttributeCount() > 0)
+ {
+ maOut.printf("%s\"attributes\" : [\n", msIndentation);
+ int nIndex = 0;
+ for (final INode aAttribute: aParent.GetAttributes())
+ {
+
+ maOut.printf("%s%s{\n", msIndentation, msSingleIndentation, nIndex++);
+
+ final String sSavedIndentation = msIndentation;
+ msIndentation += msSingleIndentation + msSingleIndentation;
+ aAttribute.AcceptVisitor(this);
+ msIndentation = sSavedIndentation;
+
+ maOut.printf("%s%s},\n", msIndentation, msSingleIndentation);
+ }
+
+ maOut.printf("%s],\n", msIndentation);
+ }
+ }
+
+
+
+
+ private void WriteLocation (
+ final INode aNode)
+ {
+ if (aNode.GetLocation() == null)
+ return;
+
+ WritePair("location", aNode.GetLocation().toString());
+ }
+
+
+
+
+ private void WritePair (
+ final String sKey,
+ final String sValue)
+ {
+ maOut.printf("%s\"%s\"%s:%s\"%s\"%s\n", msIndentation, sKey, msSpace, msSpace, sValue, ",");
+ }
+
+
+
+
+ private String Join (final Collection<String> aValues, final String sSeparator)
+ {
+ final Iterator<String> aIterator = aValues.iterator();
+ if ( ! aIterator.hasNext())
+ return "";
+
+ final StringBuffer aBuffer = new StringBuffer(aIterator.next());
+ while (aIterator.hasNext())
+ {
+ aBuffer.append(sSeparator);
+ aBuffer.append(aIterator.next());
+ }
+ return aBuffer.toString();
+ }
+
+
+
+
+ private String QuoteString (final String sValue)
+ {
+ return sValue.replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;");
+ }
+
+
+
+
+ private final SchemaBase maSchemaBase;
+ private final Map<String, Schema> maTopLevelSchemas;
+ private final PrintStream maOut;
+ private String msIndentation;
+ private final String msSingleIndentation;
+ private final String msSpace;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/code.js b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/code.js
new file mode 100644
index 000000000000..64be9682e913
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/code.js
@@ -0,0 +1,442 @@
+function LoadData ()
+{
+ gTypeNames = [];
+ ComplexTypeNames = [];
+ SimpleTypeNames = [];
+ for (var sName in Data)
+ {
+ gTypeNames.push(sName);
+ switch(Data[sName].type)
+ {
+ case "complex-type":
+ ComplexTypeNames.push(sName);
+ break;
+
+ case "simple-type":
+ SimpleTypeNames.push(sName);
+ break;
+ }
+ }
+ document.getElementById("message").innerHTML = "there are " + ComplexTypeNames.length + " complex types and "
+ + SimpleTypeNames.length +" simple types";
+}
+
+
+
+
+function InitializeSearch ()
+{
+ CurrentTypeName = "";
+ TypeHistory = Array();
+ LoadData();
+ ShowType("A:ST_Overlap");
+}
+
+
+
+
+function CheckInput (aField, aEvent)
+{
+ switch(aEvent.keyCode)
+ {
+ case 38:
+ --selection_index;
+ if (selection_index < 0)
+ selection_index = matches.length-1;
+ break;
+ case 40:
+ ++selection_index;
+ if (selection_index >= matches.length)
+ selection_index = 0;
+ break;
+ default:
+ matches = GetMatches(aField.value);
+ selection_index = 0;
+ }
+
+ ShowMatches(matches, selection_index);
+}
+
+
+
+
+function GetMatches (sPattern)
+{
+ var aLcPatterns = sPattern.toLowerCase().split(/\s+/);
+
+ var nTypeCount = gTypeNames.length;
+
+ var aMatches = [];
+ for (index=0; index<nTypeCount; ++index)
+ {
+ var sTypeName = gTypeNames[index];
+ var aParts = new Array(sTypeName);
+ var sLcTypeName = sTypeName.toLowerCase();
+ var bIsMatch = true;
+ var nSearchStart = 0;
+ for (nPatternIndex=0; nPatternIndex<aLcPatterns.length && bIsMatch; ++nPatternIndex)
+ {
+ var sPattern = aLcPatterns[nPatternIndex];
+ var nMatchStart = sLcTypeName.indexOf(sPattern, nSearchStart);
+ if (nMatchStart >= 0)
+ {
+ var nMatchEnd = nMatchStart + sPattern.length;
+ aParts.push(sTypeName.substring(nSearchStart, nMatchStart));
+ aParts.push(sTypeName.substring(nMatchStart, nMatchEnd));
+ nSearchStart = nMatchEnd;
+ }
+ else
+ {
+ // Only some patterns are matched.
+ bIsMatch = false;
+ }
+ }
+ if (bIsMatch)
+ {
+ if (nMatchEnd < sTypeName.length-1)
+ aParts.push(sTypeName.substring(nMatchEnd));
+ aMatches.push(aParts);
+ }
+ }
+ return aMatches;
+}
+
+
+
+
+/** Show the matching types.
+ * As there can be a great many matching types, some sort of abbreviation is necessary.
+ * Format all matches into lines of n entries.
+ * Show the line containing the selected match and the ones before and after.
+ * Show also the number of ommited matches.
+ */
+function ShowMatches (aMatches, nSelectionIndex)
+{
+ var sText = "";
+
+ var nHalfRange = 10;
+ var nMatchesPerLine = 5;
+ var nLineCount = Math.floor((aMatches.length+nMatchesPerLine-1) / nMatchesPerLine);
+ var nLineOfSelection = Math.floor(nSelectionIndex / nMatchesPerLine);
+ var nFirstDisplayedLine = nLineOfSelection>0 ? nLineOfSelection-1 : 0;
+ var nLastDisplayedLine = nLineOfSelection<nLineCount-1 ? nLineOfSelection+1 : nLineCount-1;
+
+ for (nLineIndex=nFirstDisplayedLine; nLineIndex<=nLastDisplayedLine; ++nLineIndex)
+ {
+ var nLineStartIndex = nLineIndex * nMatchesPerLine;
+ var nLineEndIndex = nLineStartIndex + nMatchesPerLine - 1;
+ if (nLineEndIndex >= aMatches.length)
+ nLineEndIndex = aMatches.length-1;
+
+ sText += "<tr>"
+ for (nIndex=nLineStartIndex; nIndex<=nLineEndIndex; ++nIndex)
+ {
+ var aMatch = aMatches[nIndex];
+ var sTypeName = aMatch[0];
+ var sMatch = "";
+ for (nPartIndex=1; nPartIndex<aMatch.length; ++nPartIndex)
+ {
+ if ((nPartIndex%2)==0)
+ sMatch += "<span class=\"match-highlight\">"+aMatch[nPartIndex]+"</span>";
+ else
+ sMatch += aMatch[nPartIndex];
+ }
+ sText += "<td>"
+ if (nIndex == nSelectionIndex)
+ {
+ sText += " <span class=\"typelink current-match\">" + sMatch + "</span>";
+ }
+ else
+ {
+ sText += " " + GetTypeLink(sMatch, sTypeName, -1);
+ }
+ sText += "</td>"
+ }
+
+ sText += "</tr>";
+ }
+ if (nFirstDisplayedLine > 0)
+ sText = "<tr><td>["+(nFirstDisplayedLine*nMatchesPerLine)+" matches] ...</td><tr>" + sText;
+ if (nLastDisplayedLine+1 < nLineCount)
+ sText += "<tr><td>... ["+((nLineCount-nLastDisplayedLine-1)*nMatchesPerLine)+" matches]</td></tr>";
+
+ document.getElementById('matches').innerHTML = "<table>"+sText+"</table>";
+ if (aMatches.length == 0)
+ {
+ document.getElementById('match-count').innerHTML = "no match:";
+ }
+ else
+ {
+ if (aMatches.length == 1)
+ document.getElementById('match-count').innerHTML = "single match:";
+ else
+ document.getElementById('match-count').innerHTML = aMatches.length+" matches:";
+
+ ShowType(aMatches[nSelectionIndex][0]);
+ }
+}
+
+
+
+
+function GetTopLevelNodeForTypeName(sTypeName)
+{
+ if (sTypeName in Data)
+ return Data[sTypeName];
+ else
+ alert(sTypeName +" is not a known complex type, simple type, or group");
+}
+
+
+
+
+/** Show the specified type.
+ * When nHistoryIndex is not -1 then the history is shortened to that (before that) index.
+ */
+function ShowType (sTypeName, nHistoryIndex)
+{
+ if (nHistoryIndex == -1)
+ {
+ if (CurrentTypeName != "")
+ {
+ TypeHistory.push(CurrentTypeName);
+ ShowHistory();
+ }
+ }
+ else
+ {
+ TypeHistory = TypeHistory.slice(0,nHistoryIndex);
+ ShowHistory();
+ }
+ CurrentTypeName = sTypeName;
+
+ var aElement = document.getElementById('result');
+
+ // Remove the old content.
+ while(aElement.childNodes.length > 0)
+ aElement.removeChild(aElement.firstChild);
+
+ // Create the new content.
+ var list = CreateDomTreeForType(GetTopLevelNodeForTypeName(sTypeName), "ul");
+
+ // Show the new content.
+ aElement.appendChild(list);
+}
+
+
+
+
+/** Create a dom sub tree for the given OOXML type that is ready for insertion into the global DOM tree.
+ */
+function CreateDomTreeForType (aNode, sType)
+{
+ var aEntry = document.createElement(sType);
+
+ if (typeof aNode==='undefined')
+ {
+ aEntry.innerHTML = "undefined node";
+ }
+ else if (typeof aNode.type==='undefined')
+ {
+ aEntry.innerHTML = "unknown type";
+ }
+ else
+ {
+ switch(aNode.type)
+ {
+ case "attribute":
+ aEntry.innerHTML = CreateValueTable([
+ "attribute",
+ "type:", GetTypeLink(aNode["value-type"], aNode["value-type"], -1),
+ "use:", aNode.use]);
+ break;
+
+ case "attribute-reference":
+ aEntry.innerHTML = CreateReference(aNode["referenced-attribute"]);
+ break;
+
+ case "builtin":
+ aEntry.innerHTML = CreateValueTable(
+ ["builtin",
+ "name:", aNode['builtin-type']
+ ]);
+ break;
+
+ case "complex-type":
+ aEntry.innerHTML = aNode.type + " " + aNode.name;
+ break;
+
+ case "complex-type-reference":
+ aEntry.innerHTML = CreateReference(aNode["referenced-complex-type"]);
+ break;
+
+ case "group":
+ aEntry.innerHTML = aNode.type + " " + aNode.name;
+ break;
+
+ case "group-reference":
+ aEntry.innerHTML = CreateReference("group", aNode["referenced-group"]);
+ break;
+
+ case "element":
+ aEntry.innerHTML = "element <b>" + aNode["tag"] + "</b> -> " + GetTypeLink(aNode["result-type"], aNode["result-type"], -1);
+ break;
+
+ case "occurrence":
+ aEntry.innerHTML = aNode.minimum +" -> " + aNode.maximum;
+ break;
+
+ case "restriction":
+ aEntry.innerHTML = CreateRestrictionRepresentation(aNode);
+ break;
+
+ case "sequence":
+ aEntry.innerHTML = "sequence";
+ break;
+
+ case "simple-type":
+ aEntry.innerHTML = aNode.type + " " + aNode.name;
+ break;
+
+ case "simple-type-reference":
+ aEntry.innerHTML = CreateReference("simple-type", aNode["referenced-simple-type"]);
+ break;
+
+ default:
+ aEntry.innerHTML = aNode.type;
+ break;
+ }
+
+ // Add nodes for attributes.
+ var aAttributes= aNode["attributes"];
+ if ( ! (typeof aAttributes==='undefined' || aAttributes.length == 0))
+ {
+ var aAttributeList = document.createElement("ul");
+ aEntry.appendChild(aAttributeList);
+
+ for (var nIndex=0; nIndex<aAttributes.length; ++nIndex)
+ {
+ var aAttributeEntry = CreateDomTreeForType(aAttributes[nIndex], "li");
+ aAttributeList.appendChild(aAttributeEntry);
+ }
+ }
+
+ // Add nodes for children.
+ var aChildren = aNode["children"];
+ if ( ! (typeof aChildren==='undefined' || aChildren.length == 0))
+ {
+ var aChildrenList = document.createElement("ul");
+ aEntry.appendChild(aChildrenList);
+
+ for (var nIndex=0; nIndex<aChildren.length; ++nIndex)
+ {
+ var aChildrenEntry = CreateDomTreeForType(aChildren[nIndex], "li");
+ aChildrenList.appendChild(aChildrenEntry);
+ }
+ }
+ }
+ return aEntry;
+}
+
+
+
+
+function GetTypeLink (sText, sTarget, nIndex)
+{
+ return "<span class=\"typelink\" id=\""+sTarget+"\" onclick=\"ShowType('"+sTarget+"',"+nIndex+")\">"+sText+"</span>";
+}
+
+
+
+
+function CreateValueTable (aValues)
+{
+ var sResult = "<table class=\"value-table\"><tr><td>"+aValues[0]+"</td><td>"+aValues[1]+"</td><td>"+aValues[2]+"</td></tr>";
+ for (nIndex=3; nIndex<aValues.length; nIndex+=2)
+ {
+ sResult += "<tr><td></td><td>"+aValues[nIndex]+"</td><td>"+aValues[nIndex+1]+"</td></tr>";
+ }
+ sResult += "</table>";
+ return sResult;
+}
+
+
+
+
+function CreateReference (sWhat, sTypeName)
+{
+ return "reference to "+sWhat+" "+GetTypeLink(sTypeName, sTypeName, -1) + " "
+ +CreateButton(
+ sTypeName,
+ "show",
+ "ToggleTypeReferenceExpansion('"+sTypeName+"')")
+ +"<br><span id=\"expansion-"+sTypeName+"\"></span>";
+}
+
+
+
+
+function CreateButton (sId, sText, sExpandAction)
+{
+ return "<span class=\"button\" id=\"button-"+sId+"\" onClick=\""+sExpandAction+"\">"+sText+"</span>";
+}
+
+
+
+
+function ToggleTypeReferenceExpansion(sTypeName)
+{
+ var aButton = document.getElementById("button-"+sTypeName);
+ var aExpansion = document.getElementById("expansion-"+sTypeName);
+ if (aButton.innerHTML == "show")
+ {
+ aExpansion.appendChild(CreateDomTreeForType(Data[sTypeName], "span"));
+ aButton.innerHTML = "hide";
+ }
+ else
+ {
+ aExpansion.innerHTML = "";
+ aButton.innerHTML = "show";
+ }
+}
+
+
+
+
+function ShowHistory ()
+{
+ var aElement = document.getElementById('history');
+ var sContent = "History:";
+ for (nIndex=0; nIndex<TypeHistory.length; ++nIndex)
+ {
+ if (nIndex == 0)
+ sContent += " ";
+ else
+ sContent += ", ";
+ sContent += GetTypeLink(TypeHistory[nIndex], TypeHistory[nIndex], nIndex);
+ }
+ aElement.innerHTML = sContent;
+}
+
+
+
+
+function CreateRestrictionRepresentation (aNode)
+{
+ var aTableData = ["restriction", "based on:", GetTypeLink(aNode['base-type'], aNode['base-type'], -1)];
+ AddValue(aNode, "enumeration", aTableData);
+ AddValue(aNode, "pattern", aTableData);
+ AddValue(aNode, "length", aTableData);
+ return CreateValueTable(aTableData);
+}
+
+
+
+function AddValue (aMap, sKey, aTableData)
+{
+ if (sKey in aMap)
+ {
+ aTableData.push(sKey+":");
+ aTableData.push(aMap[sKey]);
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/display.css b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/display.css
new file mode 100644
index 000000000000..d7d267e9ed9d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/display.css
@@ -0,0 +1,57 @@
+* {
+ font-family: Arial;
+ font-style:normal;
+ }
+.typelink {
+ cursor: pointer; cursor: hand;
+ color: #688;
+ }
+.typelink:link { color:#003; background-color:transparent; }
+.typelink:visited { color:#003; background-color:transparent; }
+.typelink:hover {
+ text-decoration: underline;
+ }
+.typelink:active { color:#003; background-color:#acc; }
+
+.value-table { display: inline-table; }
+
+
+.button {
+ box-shadow:inset 0px 1px 0px 0px #ffffff;
+ background-color:#ededed;
+ border-top-left-radius:4px;
+ border-top-right-radius:4px;
+ border-bottom-right-radius:4px;
+ border-bottom-left-radius:4px;
+ border:1px solid #dcdcdc;
+ display: inline-block;
+ color: #777777;
+ font-size: 15px;
+ font-weight: bold;
+ height: 20px;
+ line-height: 20px;
+ width: 80px;
+ text-align:center;
+ vertical-align: middle;
+ text-shadow:1px 1px 0px #ffffff;
+ cursor: pointer; cursor: hand;
+ }
+
+.button:hover {
+ background-color:#dfdfdf;
+ }
+
+.button:active {
+ position: relative;
+ top: 1px;
+ background-color:#c0c0c0;
+ }
+
+.current-match {
+ font-weight: bold;
+ background-color:#c0c0c0;
+ }
+
+.match-highlight {
+ color: #ff0000;
+ }
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/linking-template.html b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/linking-template.html
new file mode 100644
index 000000000000..c20c67c57165
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/linking-template.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <link rel="stylesheet" type="text/css" href="C:\source\ooxml\git\main\ooxml\source\framework\SchemaParser\src\org\apache\openoffice\ooxml\schema\generator\html\display.css">
+ </link>
+ <script type="text/javascript">
+ $DATA$
+ </script>
+ <script type="text/javascript" src="C:\source\ooxml\git\main\ooxml\source\framework\SchemaParser\src\org\apache\openoffice\ooxml\schema\generator\html\code.js">
+ </script>
+ </head>
+ <body onLoad="InitializeSearch()">
+ <div id="message"></div>
+ <input onKeyUp="CheckInput(this,event)"></input>
+ <div id="history"></div>
+ <br><br><div id="match-count">Matches:</div><br>
+ <div id="matches" cols="100" rows="20" defaultValue="type text to see matching types"></div>
+ <br>
+ <div id="result">no result yet</div>
+ </body>
+</html>
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/template.html b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/template.html
new file mode 100644
index 000000000000..2c174c137717
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/template.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <style type="text/css">
+ $CSS$
+ </style>
+ <script type="text/javascript">
+ $DATA$
+ </script>
+ <script type="text/javascript">
+ $CODE$
+ </script>
+ </head>
+ <body onLoad="InitializeSearch()">
+ <div id="message"></div>
+ <input onKeyUp="CheckInput(this,event)"></input>
+ <br><br><div id="match-count">Matches:</div><br>
+ <div id="history"></div>
+ <div id="matches" cols="100" rows="20" defaultValue="type text to see matching types"></div>
+ <br>
+ <div id="result">no result yet</div>
+ </body>
+</html>
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeIterator.java
new file mode 100644
index 000000000000..2160b8b26623
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeIterator.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* 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.iterator;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Iterate over all attributes of a given node.
+ * References to attributes and attribute groups and their references are resolved.
+ *
+ * If you want to iterate over all attributes in a node tree then add an outer NodeIterator.
+ */
+public class AttributeIterator
+ implements Iterable<Attribute>
+{
+ public AttributeIterator (
+ final INode aNode,
+ final SchemaBase aSchemaBase)
+ {
+ maAttributes = new TreeSet<Attribute>();
+ CollectAttributes(aNode, aSchemaBase);
+ }
+
+
+
+
+ public Iterator<Attribute> iterator ()
+ {
+ return maAttributes.iterator();
+ }
+
+
+
+
+ private void CollectAttributes (
+ final INode aType,
+ final SchemaBase aSchemaBase)
+ {
+ final Queue<INode> aTodo = new LinkedList<>();
+ for (final INode aAttribute : aType.GetAttributes())
+ aTodo.add(aAttribute);
+ final INodeVisitor aVisitor = new NodeVisitorAdapter()
+ {
+ @Override public void Visit (final Attribute aAttribute)
+ {
+ maAttributes.add(aAttribute);
+ }
+ @Override public void Visit (final AttributeReference aAttributeReference)
+ {
+ aTodo.add(aAttributeReference.GetReferencedAttribute(aSchemaBase));
+ }
+ @Override public void Visit (final AttributeGroup aAttributeGroup)
+ {
+ for (final INode aGroupAttribute : aAttributeGroup.GetAttributes())
+ aTodo.add(aGroupAttribute);
+ }
+ @Override public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ aTodo.add(aAttributeGroupReference.GetReferencedAttributeGroup(aSchemaBase));
+ }
+ @Override public void Default (final INode aNode)
+ {
+ throw new RuntimeException("can not handle attribute of type "+aNode.GetNodeType());
+ }
+ };
+ while ( ! aTodo.isEmpty())
+ {
+ final INode aAttribute = aTodo.poll();
+ if (aAttribute != null)
+ aAttribute.AcceptVisitor(aVisitor);
+ }
+ }
+
+
+
+
+ private final Set<Attribute> maAttributes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeNodeIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeNodeIterator.java
new file mode 100644
index 000000000000..0a5bc410f073
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeNodeIterator.java
@@ -0,0 +1,112 @@
+/**************************************************************
+*
+* 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.iterator;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** This iterator is very similar to the AttributeIterator but it
+ * a) returns the attributes as INode objects and
+ * b) includes referencing nodes and group nodes in the iteration and
+ * c) if there are multiple references to the same attribute then each
+ * of them is visited.
+ */
+public class AttributeNodeIterator
+ implements Iterable<INode>
+{
+ public AttributeNodeIterator (
+ final INode aNode,
+ final SchemaBase aSchemaBase)
+ {
+ maAttributes = new Vector<INode>();
+ CollectAttributes(aNode, aSchemaBase);
+ }
+
+
+
+
+ public Iterator<INode> iterator ()
+ {
+ return maAttributes.iterator();
+ }
+
+
+
+
+ private void CollectAttributes (
+ final INode aType,
+ final SchemaBase aSchemaBase)
+ {
+ final Queue<INode> aTodo = new LinkedList<>();
+ for (final INode aAttribute : aType.GetAttributes())
+ aTodo.add(aAttribute);
+ final INodeVisitor aVisitor = new NodeVisitorAdapter()
+ {
+ @Override public void Visit (final Attribute aAttribute)
+ {
+ maAttributes.add(aAttribute);
+ }
+ @Override public void Visit (final AttributeReference aAttributeReference)
+ {
+ maAttributes.add(aAttributeReference);
+ aTodo.add(aAttributeReference.GetReferencedAttribute(aSchemaBase));
+ }
+ @Override public void Visit (final AttributeGroup aAttributeGroup)
+ {
+ maAttributes.add(aAttributeGroup);
+ for (final INode aGroupAttribute : aAttributeGroup.GetAttributes())
+ aTodo.add(aGroupAttribute);
+ }
+ @Override public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ maAttributes.add(aAttributeGroupReference);
+ aTodo.add(aAttributeGroupReference.GetReferencedAttributeGroup(aSchemaBase));
+ }
+ @Override public void Default (final INode aNode)
+ {
+ throw new RuntimeException("can not handle attribute of type "+aNode.GetNodeType());
+ }
+ };
+ while ( ! aTodo.isEmpty())
+ {
+ final INode aAttribute = aTodo.poll();
+ if (aAttribute != null)
+ aAttribute.AcceptVisitor(aVisitor);
+ }
+ }
+
+
+
+
+ private final Vector<INode> maAttributes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/DereferencingNodeIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/DereferencingNodeIterator.java
new file mode 100644
index 000000000000..77c8f9837c55
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/DereferencingNodeIterator.java
@@ -0,0 +1,111 @@
+/**************************************************************
+*
+* 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.iterator;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Iterate over all nodes in a node tree. References to groups and elements
+ * are resolved and the referenced nodes are included in the iteration.
+ */
+public class DereferencingNodeIterator
+ implements Iterable<INode>
+
+{
+ public DereferencingNodeIterator (
+ final INode aRoot,
+ final SchemaBase aSchemaBase,
+ final boolean bIncludeReferencingNodes)
+ {
+ maRoot = aRoot;
+ maSchemaBase = aSchemaBase;
+ mbIncludeReferencingNodes = bIncludeReferencingNodes;
+ }
+
+
+
+
+ @Override
+ public Iterator<INode> iterator()
+ {
+ return CollectNodes(maRoot, mbIncludeReferencingNodes).iterator();
+ }
+
+
+
+
+ private Vector<INode> CollectNodes (
+ final INode aRoot,
+ final boolean bIncludeReferencingNodes)
+ {
+ final Vector<INode> aNodes = new Vector<>();
+ AddNodes(aNodes, aRoot, bIncludeReferencingNodes);
+ return aNodes;
+ }
+
+
+
+
+ private void AddNodes (
+ final Vector<INode> aNodes,
+ final INode aRoot,
+ final boolean bIncludeReferencingNodes)
+ {
+ for (final INode aNode : new NodeIterator(aRoot))
+ {
+ switch(aNode.GetNodeType())
+ {
+ case AttributeGroupReference:
+ case AttributeReference:
+ case ComplexTypeReference:
+ case ElementReference:
+ case GroupReference:
+ case SimpleTypeReference:
+ case Extension:
+ if (mbIncludeReferencingNodes)
+ aNodes.add(aNode);
+ for (final INode aChild : new DereferencingNodeIterator(
+ ((INodeReference)aNode).GetReferencedNode(maSchemaBase),
+ maSchemaBase,
+ bIncludeReferencingNodes))
+ {
+ aNodes.add(aChild);
+ }
+ break;
+
+ default:
+ aNodes.add(aNode);
+ }
+ }
+ }
+
+
+
+
+ private final INode maRoot;
+ private final SchemaBase maSchemaBase;
+ private final boolean mbIncludeReferencingNodes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/NodeIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/NodeIterator.java
new file mode 100644
index 000000000000..8ecb2abe068c
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/NodeIterator.java
@@ -0,0 +1,68 @@
+/**************************************************************
+*
+* 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.iterator;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+
+/** Iterate over all nodes in a node tree.
+ * The root node is typically a simple or complex type.
+ * References to elements or groups etc. are not followed. Use the
+ * DereferencingNodeIterator for that.
+ */
+public class NodeIterator
+ implements Iterable<INode>
+{
+ public NodeIterator (final INode aRoot)
+ {
+ maNodes = new Vector<>();
+ AddNodes(aRoot);
+ }
+
+
+
+
+ @Override
+ public Iterator<INode> iterator ()
+ {
+ return maNodes.iterator();
+ }
+
+
+
+
+ /** Recursively add child nodes depth first.
+ */
+ private void AddNodes (final INode aNode)
+ {
+ maNodes.add(aNode);
+ for (final INode aChild : aNode.GetChildren())
+ AddNodes(aChild);
+ }
+
+
+
+
+ private Vector<INode> maNodes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/PermutationIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/PermutationIterator.java
new file mode 100644
index 000000000000..e71a6d4deac2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/PermutationIterator.java
@@ -0,0 +1,137 @@
+/**************************************************************
+*
+* 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.iterator;
+
+
+/** Enumerate all permutations of a given array with elements of type T.
+ * The permutations are created in place, i.e. the array given to the constructor
+ * is modified as side effect of calling HasMore().
+ *
+ * The algorithm is taken from "The Art of Computer Programming, Volume 4,
+ * Fasicle 2, by Donald E. Knuth" from section 7.2.1.2, Algorithm P.
+ */
+public class PermutationIterator<T>
+{
+ public PermutationIterator (
+ final T[] aItems)
+ {
+ // Count the nodes.
+ mnItemCount = aItems.length;
+
+ // Set up three arrays, one with the actual nodes, one for the inversions
+ // and one for directions.
+ maItems = aItems;
+ maInversions = new int[mnItemCount];
+ maDirections = new int[mnItemCount];
+ for (int nIndex=0; nIndex<mnItemCount; ++nIndex)
+ {
+ maInversions[nIndex] = 0;
+ maDirections[nIndex] = 1;
+ }
+
+ mbHasMorePermutations = mnItemCount>0;
+ mbIsNextPermutationReady = true;
+ }
+
+
+
+
+ public boolean HasMore ()
+ {
+ if ( ! mbIsNextPermutationReady)
+ ProvideNextPermutation();
+ return mbHasMorePermutations;
+ }
+
+
+
+
+ public T[] Next()
+ {
+ assert(mbHasMorePermutations && mbIsNextPermutationReady);
+ mbIsNextPermutationReady = false;
+ return maItems;
+ }
+
+
+
+
+ private void ProvideNextPermutation ()
+ {
+ mbIsNextPermutationReady = true;
+
+ // Create the next permutation.
+ int nJ = mnItemCount;
+ int nS = 0;
+
+ while (true)
+ {
+ final int nQ = maInversions[nJ-1] + maDirections[nJ-1];
+ if (nQ>=0 && nQ<nJ)
+ {
+ // Exchange j-cj+s and j-q+s
+ final int nIndexA = nJ-maInversions[nJ - 1]+nS - 1;
+ final int nIndexB = nJ-nQ+nS - 1;
+ final T aItem = maItems[nIndexA];
+ maItems[nIndexA] = maItems[nIndexB];
+ maItems[nIndexB] = aItem;
+
+ // cj=q
+ maInversions[nJ - 1] = nQ;
+
+ // Next permutation is ready.
+ break;
+ }
+ else
+ {
+ if (nQ==nJ)
+ {
+ // Increase s.
+ if (nJ == 1)
+ {
+ // All permutations generated.
+ mbHasMorePermutations = false;
+ break;
+ }
+ else
+ {
+ ++nS;
+ }
+ }
+
+ // Switch direction.
+ maDirections[nJ - 1] = -maDirections[nJ - 1];
+ --nJ;
+ }
+ }
+ }
+
+
+
+
+ private final int mnItemCount;
+ private final T[] maItems;
+ private final int[] maInversions;
+ private final int[] maDirections;
+ private boolean mbIsNextPermutationReady;
+ private boolean mbHasMorePermutations;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/misc/Log.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/misc/Log.java
new file mode 100644
index 000000000000..8ac464743dae
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/misc/Log.java
@@ -0,0 +1,126 @@
+/**************************************************************
+*
+* 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.misc;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+/** Make output with indentation easier.
+ */
+public class Log
+{
+ public Log (final File aFile)
+ {
+ PrintStream aOut = null;
+ try
+ {
+ aOut = new PrintStream(new FileOutputStream(aFile));
+ }
+ catch (FileNotFoundException e)
+ {
+ e.printStackTrace();
+ }
+ maOut = aOut;
+ mbIsActive = maOut!=null;
+ msIndentation = "";
+ }
+
+
+
+
+ public void AddComment (
+ final String sFormat,
+ final Object ... aArgumentList)
+ {
+ if (mbIsActive)
+ {
+ maOut.print(msIndentation);
+ maOut.print("// ");
+ maOut.printf(sFormat, aArgumentList);
+ maOut.print("\n");
+ }
+ }
+
+
+
+
+ public void StartBlock ()
+ {
+ if (mbIsActive)
+ msIndentation += " ";
+ }
+
+
+
+
+ public void EndBlock ()
+ {
+ if (mbIsActive)
+ msIndentation = msIndentation.substring(4);
+ }
+
+
+
+
+ public void printf (
+ final String sFormat, final Object ... aArgumentList)
+ {
+ if (mbIsActive)
+ {
+ final String sMessage = String.format(sFormat, aArgumentList);
+ maOut.print(msIndentation);
+ maOut.print(sMessage);
+ }
+ }
+
+
+
+
+ public void println (
+ final String sMessage)
+ {
+ if (mbIsActive)
+ {
+ maOut.print(msIndentation);
+ maOut.print(sMessage);
+ maOut.print("\n");
+ }
+ }
+
+
+
+
+ public void Close()
+ {
+ if (mbIsActive)
+ maOut.close();
+ }
+
+
+
+
+ private final PrintStream maOut;
+ private final boolean mbIsActive;
+ private String msIndentation;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/Attribute.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/Attribute.java
new file mode 100644
index 000000000000..84f68cb77354
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/Attribute.java
@@ -0,0 +1,91 @@
+/**************************************************************
+*
+* 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.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.parser.FormDefault;
+
+/* Representation of a single attribute.
+ */
+public class Attribute
+ extends AttributeBase
+{
+ public Attribute (
+ final QualifiedName aName,
+ final QualifiedName aTypeName,
+ final String sUse,
+ final String sDefault,
+ final String sFixed,
+ final FormDefault eFormDefault,
+ final Location aLocation)
+ {
+ super(aName, sUse, sDefault, sFixed, eFormDefault, aLocation);
+ maTypeName = aTypeName;
+ }
+
+
+
+
+ public QualifiedName GetTypeName ()
+ {
+ return maTypeName;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Attribute;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format(
+ "attribute %s of type %s, %s",
+ GetName().GetDisplayName(),
+ maTypeName.GetDisplayName(),
+ super.toString());
+ }
+
+
+
+
+ private final QualifiedName maTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeBase.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeBase.java
new file mode 100644
index 000000000000..4fbf987a5be7
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeBase.java
@@ -0,0 +1,117 @@
+/**************************************************************
+*
+* 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.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.parser.FormDefault;
+
+/** Base class for both Attribute and AttributeReference classes.
+ */
+public abstract class AttributeBase
+ extends Node
+{
+ public enum Use
+ {
+ Optional,
+ Required
+ }
+
+
+
+ public AttributeBase (
+ final QualifiedName aName,
+ final String sUse,
+ final String sDefault,
+ final String sFixed,
+ final FormDefault eFormDefault,
+ final Location aLocation)
+ {
+ super(null, aName, aLocation);
+
+ switch(sUse)
+ {
+ case "optional":
+ meUse = Use.Optional;
+ break;
+ case "required":
+ meUse = Use.Required;
+ break;
+ default:
+ throw new RuntimeException("value of 'use' attribute is neither 'optional' nor 'required' but "+sUse);
+ }
+ msDefault = sDefault;
+ msFixed = sFixed;
+ meFormDefault = eFormDefault;
+ }
+
+
+
+
+ public FormDefault GetFormDefault()
+ {
+ return meFormDefault;
+ }
+
+
+
+
+ public Use GetUse ()
+ {
+ return meUse;
+ }
+
+
+
+
+ public String GetDefault()
+ {
+ return msDefault;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ String sText = "use "+meUse.toString();
+ if (msDefault != null)
+ sText += ", default "+msDefault;
+ else
+ sText += ", no default";
+ if (msFixed != null)
+ sText += ", fixed to "+msFixed;
+ else
+ sText += ", not fixed";
+ return sText;
+ }
+
+
+
+
+ private final Use meUse;
+ private final String msDefault;
+ private final String msFixed;
+ private final FormDefault meFormDefault;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroup.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroup.java
new file mode 100644
index 000000000000..92b7151678d4
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroup.java
@@ -0,0 +1,65 @@
+/**************************************************************
+*
+* 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.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+public class AttributeGroup
+ extends Node
+{
+ public AttributeGroup (
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(null, aName, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.AttributeGroup;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ public String toString ()
+ {
+ return "attribute group "+GetName().GetDisplayName();
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroupReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroupReference.java
new file mode 100644
index 000000000000..aa1e7470fe0e
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroupReference.java
@@ -0,0 +1,110 @@
+/**************************************************************
+*
+* 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.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class AttributeGroupReference
+ extends Node
+ implements INodeReference
+{
+ public AttributeGroupReference (
+ final QualifiedName aReferencedElementName,
+ final Location aLocation)
+ {
+ super(null, null, aLocation);
+ maReferencedElement = aReferencedElementName;
+ }
+
+
+
+
+ @Override
+ public INode GetOnlyChild ()
+ {
+ throw new RuntimeException("AttributeGroupReference has no children");
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ public QualifiedName GetReferencedName ()
+ {
+ return maReferencedElement;
+ }
+
+
+
+
+ public AttributeGroup GetReferencedAttributeGroup (final SchemaBase aSchemaBase)
+ {
+ return aSchemaBase.AttributeGroups.Get(maReferencedElement);
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchemaBase)
+ {
+ return GetReferencedAttributeGroup(aSchemaBase);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.AttributeGroupReference;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "reference to attribute group "+maReferencedElement.GetDisplayName();
+ }
+
+
+
+
+ private final QualifiedName maReferencedElement;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeReference.java
new file mode 100644
index 000000000000..a1c97d6c2c4e
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeReference.java
@@ -0,0 +1,115 @@
+/**************************************************************
+*
+* 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.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.parser.FormDefault;
+
+public class AttributeReference
+ extends AttributeBase
+ implements INodeReference
+{
+ public AttributeReference (
+ final QualifiedName aReferencedName,
+ final String sUse,
+ final String sDefault,
+ final String sFixed,
+ final FormDefault eFormDefault,
+ final Location aLocation)
+ {
+ super(aReferencedName, sUse, sDefault, sFixed, eFormDefault, aLocation);
+
+ maReferencedName = aReferencedName;
+ }
+
+
+
+
+ public Attribute GetReferencedAttribute (final SchemaBase aSchemaBase)
+ {
+ final Attribute aAttribute = aSchemaBase.Attributes.Get(maReferencedName);
+ if (aAttribute == null)
+ {
+ throw new RuntimeException(
+ String.format(
+ "can not find attribute %s, referenced at %s",
+ maReferencedName.GetDisplayName(),
+ GetLocation()));
+ }
+ return aAttribute;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchemaBase)
+ {
+ return GetReferencedAttribute(aSchemaBase);
+ }
+
+
+
+
+ public QualifiedName GetReferencedName ()
+ {
+ return maReferencedName;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.AttributeReference;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor(INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "attribute reference to "+maReferencedName;
+ }
+
+
+
+
+ private final QualifiedName maReferencedName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INode.java
new file mode 100644
index 000000000000..df8208b9adeb
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INode.java
@@ -0,0 +1,39 @@
+/**************************************************************
+*
+* 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.model.base;
+
+
+/** Interface of all nodes in a tree of XML schema nodes.
+ * It is implemented by complex types, simple types, and attributes.
+ */
+public interface INode
+{
+ NodeType GetNodeType ();
+ QualifiedName GetName ();
+ int GetChildCount();
+ Iterable<INode> GetChildren();
+ INode GetOnlyChild();
+ int GetAttributeCount();
+ Iterable<INode> GetAttributes ();
+ void AcceptVisitor (final INodeVisitor aVisitor);
+ Location GetLocation ();
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeReference.java
new file mode 100644
index 000000000000..e4644563be14
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeReference.java
@@ -0,0 +1,32 @@
+/**************************************************************
+*
+* 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.model.base;
+
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Interface implemented by all references to INodes.
+ */
+public interface INodeReference
+ extends INode
+{
+ INode GetReferencedNode (final SchemaBase aSchema);
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeVisitor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeVisitor.java
new file mode 100644
index 000000000000..664384dced5a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeVisitor.java
@@ -0,0 +1,85 @@
+/**************************************************************
+*
+* 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.model.base;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexTypeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+/** Interface for the visitor pattern.
+ * Use a node visitor instead of INode/NodeType and casting INode to a derived
+ * class.
+ * See also the default implementation NodeVisitorAdapter.
+ */
+public interface INodeVisitor
+{
+ // Complex nodes.
+ void Visit (final All aAll);
+ void Visit (final Any aAny);
+ void Visit (final ComplexContent aComplexContent);
+ void Visit (final ComplexType aNode);
+ void Visit (final ComplexTypeReference aTypeReference);
+ void Visit (final Choice aChoice);
+ void Visit (final Element aElement);
+ void Visit (final ElementReference aElementReference);
+ void Visit (final Extension aNode);
+ void Visit (final Group aGroup);
+ void Visit (final GroupReference aGroupReference);
+ void Visit (final OccurrenceIndicator aOccurrenceIndicator);
+ void Visit (final Sequence aNode);
+
+ // Simple nodes.
+ void Visit (final BuiltIn aType);
+ void Visit (final List aList);
+ void Visit (final Restriction aRestriction);
+ void Visit (final SimpleContent aSimpleContent);
+ void Visit (final SimpleType aSimpleType);
+ void Visit (final SimpleTypeReference aSimpleTypeReference);
+ void Visit (final Union aUnion);
+
+ // Attributes.
+ void Visit (final AttributeGroup attributeGroup);
+ void Visit (final AttributeReference attributeReference);
+ void Visit (final Attribute attribute);
+ void Visit (final AttributeGroupReference attributeGroupReference);
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Location.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Location.java
new file mode 100644
index 000000000000..8ebd8093b014
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Location.java
@@ -0,0 +1,69 @@
+/**************************************************************
+*
+* 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.model.base;
+
+/** The location in a file consisting of file name, line number, column number
+ * and byte index in the file.
+ */
+public class Location
+{
+ public Location (
+ final String sFilename,
+ final int nLineNumber,
+ final int nColumnNumber,
+ final int nOffset)
+ {
+ msFilename = sFilename;
+ mnLineNumber = nLineNumber;
+ mnColumnNumber = nColumnNumber;
+ mnOffset = nOffset;
+ }
+
+
+
+
+ public Location ()
+ {
+ this("<predefined>", 0,0,0);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("%s:%d,%d/%d",
+ msFilename,
+ mnLineNumber,
+ mnColumnNumber,
+ mnOffset);
+ }
+
+
+
+
+ private final String msFilename;
+ private final int mnLineNumber;
+ private final int mnColumnNumber;
+ private final int mnOffset;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Node.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Node.java
new file mode 100644
index 000000000000..b965b0dba1cc
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Node.java
@@ -0,0 +1,172 @@
+/**************************************************************
+*
+* 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.model.base;
+
+import java.util.Vector;
+
+/** Base class for the nodes in the type hierarchies that represent complex
+ * types, simple types, and attributes.
+ */
+public abstract class Node
+ implements INode, Comparable<Node>
+{
+ abstract public NodeType GetNodeType ();
+
+
+
+ protected Node (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ maParent = aParent;
+ maName = aName;
+
+ maLocation = aLocation;
+ maAttributes = new Vector<>();
+ maChildren = new Vector<>();
+ }
+
+
+
+
+ @Override
+ public QualifiedName GetName ()
+ {
+ return maName;
+ }
+
+
+
+
+ public Node GetParent ()
+ {
+ return maParent;
+ }
+
+
+
+
+ /** Store the location in the schema files. This is used for debugging or the creation of documentation.
+ */
+ public void SetLocation (
+ final Location aLocation)
+ {
+ maLocation = aLocation;
+ }
+
+
+
+
+ public Location GetLocation ()
+ {
+ return maLocation;
+ }
+
+
+
+
+ public void AddAttribute (final INode aAttribute)
+ {
+ maAttributes.add(aAttribute);
+ }
+
+
+
+
+ @Override
+ public int GetAttributeCount ()
+ {
+ return maAttributes.size();
+ }
+
+
+
+
+ @Override
+ public Iterable<INode> GetAttributes ()
+ {
+ return maAttributes;
+ }
+
+
+
+ public void ClearChildren ()
+ {
+ maChildren.clear();
+ }
+
+
+
+ public void AddChild (final INode aChild)
+ {
+ maChildren.add(aChild);
+ }
+
+
+
+
+ public Iterable<INode> GetChildren ()
+ {
+ return maChildren;
+ }
+
+
+
+
+ public INode GetOnlyChild ()
+ {
+ assert(maChildren.size() == 1);
+ return maChildren.get(0);
+ }
+
+
+
+
+ public int GetChildCount ()
+ {
+ return maChildren.size();
+ }
+
+
+
+
+ @Override
+ public int compareTo (final Node aOther)
+ {
+ if (maName==null || aOther.maName==null)
+ {
+ throw new RuntimeException("can not compare nodes that don't have a name");
+ }
+ else
+ return maName.compareTo(aOther.maName);
+ }
+
+
+
+
+ private final Node maParent;
+ private final QualifiedName maName;
+ private Location maLocation;
+ private final Vector<INode> maAttributes;
+ private final Vector<INode> maChildren;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeType.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeType.java
new file mode 100644
index 000000000000..98649af621f2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeType.java
@@ -0,0 +1,53 @@
+/**************************************************************
+*
+* 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.model.base;
+
+/** Type of a node in the XML schema tree.
+ * It basically corresponds to the class of a node.
+ */
+public enum NodeType
+{
+ All,
+ Any,
+ Attribute,
+ AttributeReference,
+ AttributeGroup,
+ AttributeGroupReference,
+ BuiltIn,
+ Choice,
+ ComplexContent,
+ ComplexType,
+ ComplexTypeReference,
+ Element,
+ ElementReference,
+ Extension,
+ Group,
+ GroupReference,
+ List,
+ OccurrenceIndicator,
+ Restriction,
+ Sequence,
+ SimpleContent,
+ SimpleType,
+ SimpleTypeReference,
+ Union
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeVisitorAdapter.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeVisitorAdapter.java
new file mode 100644
index 000000000000..2096d8df95ee
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeVisitorAdapter.java
@@ -0,0 +1,203 @@
+/**************************************************************
+*
+* 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.model.base;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexTypeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+/** Implementation of the INodeVisitor interface.
+ * All methods that are not overridden are redirected to the Default(INode)
+ * method.
+ */
+public class NodeVisitorAdapter
+ implements INodeVisitor
+{
+ @Override
+ public void Visit (final All aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final Any aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final Choice aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final ComplexContent aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final ComplexType aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final ComplexTypeReference aTypeReference)
+ {
+ Default(aTypeReference);
+ }
+
+ @Override
+ public void Visit (final Element aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final ElementReference aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final Extension aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final Group aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final GroupReference aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final OccurrenceIndicator aIndicator)
+ {
+ Default(aIndicator);
+ }
+
+ @Override
+ public void Visit(Sequence aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final BuiltIn aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit (final List aList)
+ {
+ Default(aList);
+ }
+
+ @Override
+ public void Visit (final SimpleContent aSimpleContent)
+ {
+ Default(aSimpleContent);
+ }
+
+ @Override
+ public void Visit (final SimpleType aSimpleType)
+ {
+ Default(aSimpleType);
+ }
+
+ @Override
+ public void Visit (final SimpleTypeReference aSimpleTypeReference)
+ {
+ Default(aSimpleTypeReference);
+ }
+
+ @Override
+ public void Visit (final Union aUnion)
+ {
+ Default(aUnion);
+ }
+
+ @Override
+ public void Visit (final Restriction aRestriction)
+ {
+ Default(aRestriction);
+ }
+
+ @Override
+ public void Visit (final AttributeGroup aAttributeGroup)
+ {
+ Default(aAttributeGroup);
+ }
+
+ @Override
+ public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ Default(aAttributeGroupReference);
+ }
+
+ @Override
+ public void Visit (final AttributeReference aAttributeReference)
+ {
+ Default(aAttributeReference);
+ }
+
+ @Override
+ public void Visit (final Attribute aAttribute)
+ {
+ Default(aAttribute);
+ }
+
+ public void Default (final INode aNode)
+ {
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/QualifiedName.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/QualifiedName.java
new file mode 100644
index 000000000000..d56df52cb8cf
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/QualifiedName.java
@@ -0,0 +1,149 @@
+/**************************************************************
+*
+* 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.model.base;
+
+import javax.xml.namespace.QName;
+
+/** Similar to the QName class. A qualified name that consists of the local
+ * part and a namespace.
+ * The namespace is stored both as URI and short form (prefix).
+ */
+public class QualifiedName
+ implements Comparable<QualifiedName>
+{
+ public QualifiedName (final QName aName)
+ {
+ msLocalPart = aName.getLocalPart();
+ msNamespacePrefix = aName.getPrefix();
+ msNamespaceURI = aName.getNamespaceURI();
+ }
+
+
+
+
+ public QualifiedName (
+ final String sNamespaceURI,
+ final String sNamespacePrefix,
+ final String sLocalPart)
+ {
+ msLocalPart = sLocalPart;
+ msNamespacePrefix = sNamespacePrefix;
+ msNamespaceURI = sNamespaceURI;
+ }
+
+
+
+
+ public QualifiedName (final String sLocalPart)
+ {
+ this(null, null, sLocalPart);
+ }
+
+
+
+
+ /** Return a textual representation for informal (and informative) display.
+ */
+ public String GetDisplayName ()
+ {
+ if (msNamespacePrefix == null)
+ return msLocalPart;
+ else
+ return msNamespacePrefix + ":" + msLocalPart;
+ }
+
+
+
+
+ public String GetStateName()
+ {
+ if (msNamespacePrefix == null)
+ return msLocalPart;
+ else
+ return msNamespacePrefix + "_" + msLocalPart;
+ }
+
+
+
+
+ public String GetNamespaceURI ()
+ {
+ return msNamespaceURI;
+ }
+
+
+
+
+ public String GetNamespacePrefix ()
+ {
+ return msNamespacePrefix;
+ }
+
+
+
+
+ public String GetLocalPart ()
+ {
+ return msLocalPart;
+ }
+
+
+
+
+ /** Compare QualifiedName objects (e.g. for sorting them).
+ * Primary sort key is the local part.
+ * Secondary key is the namespace prefix.
+ * Missing prefixes come before existing prefixes.
+ */
+ @Override
+ public int compareTo (final QualifiedName aOther)
+ {
+ final int nComparisonResult = msLocalPart.compareTo(aOther.msLocalPart);
+ if (nComparisonResult != 0)
+ return nComparisonResult;
+ else
+ if (msNamespacePrefix==null && aOther.msNamespacePrefix==null)
+ return 0;
+ else if (msNamespacePrefix!=null && aOther.msNamespacePrefix!=null)
+ return msNamespacePrefix.compareTo(aOther.msNamespacePrefix);
+ else if (msNamespacePrefix==null)
+ return -1;
+ else
+ return +1;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return GetDisplayName();
+ }
+
+
+
+
+ private final String msLocalPart;
+ private final String msNamespacePrefix;
+ private final String msNamespaceURI;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/All.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/All.java
new file mode 100644
index 000000000000..cb1de8adf2b9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/All.java
@@ -0,0 +1,96 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** Representation of the 'all' XML schema element. All its children are
+ * expected to occur in any order. By default each child is optional but with
+ * a min=1 attribute the children can be made mandatory.
+ */
+public class All
+ extends Node
+{
+ public All (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+
+ assert(CheckParent(aParent));
+ }
+
+
+
+
+ /** Occurrence values of an 'all' node must be
+ * min=(0,1)
+ * max=1.
+ */
+ private static boolean CheckParent (final Node aParent)
+ {
+ if (aParent == null)
+ return false;
+ if (aParent.GetNodeType() != NodeType.OccurrenceIndicator)
+ // Missing occurrence parent means that min and max have the default
+ // values of 0 and 1, which is valid.
+ return true;
+
+ final OccurrenceIndicator aIndicator = (OccurrenceIndicator)aParent;
+ if (aIndicator.GetMinimum() > 1)
+ return false;
+ else if (aIndicator.GetMaximum() != 1)
+ return false;
+ else
+ return true;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.All;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "all";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Any.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Any.java
new file mode 100644
index 000000000000..cc2573b86d46
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Any.java
@@ -0,0 +1,112 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** Representation of the 'any' XML schema element. It specifies that its
+ * children conform to a non-standard schema. If it is unknown than the
+ * children are to be ignored.
+ */
+public class Any
+ extends Node
+{
+ public enum ProcessContents
+ {
+ lax,
+ skip,
+ strict
+ }
+
+ public Any (
+ final Node aParent,
+ final Location aLocation,
+ final String sProcessContents,
+ final String sNamespace)
+ {
+ super(aParent, null, aLocation);
+ meProcessContents = ProcessContents.valueOf(sProcessContents);
+ maNamespaces = sNamespace.split("\\s+");
+ }
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Any;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+ public ProcessContents GetProcessContentsFlag ()
+ {
+ return meProcessContents;
+ }
+
+
+
+
+ public String[] GetNamespaces ()
+ {
+ return maNamespaces;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ final StringBuffer aBuffer = new StringBuffer();
+ aBuffer.append("any processContents=");
+ aBuffer.append(meProcessContents.toString());
+ aBuffer.append(", namespaces=");
+ boolean bFirst = true;
+ for (final String sNamespace : maNamespaces)
+ {
+ if (bFirst)
+ bFirst = false;
+ else
+ aBuffer.append('|');
+ aBuffer.append(sNamespace);
+ }
+ return aBuffer.toString();
+ }
+
+
+
+
+ private final ProcessContents meProcessContents;
+ private final String[] maNamespaces;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Choice.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Choice.java
new file mode 100644
index 000000000000..ab00f1237e3e
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Choice.java
@@ -0,0 +1,68 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** Representation of the 'choice' XML schema element.
+ * With the default max value (1) only one of its children may occur.
+ */
+public class Choice
+ extends Node
+{
+ public Choice (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Choice;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "choice";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexContent.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexContent.java
new file mode 100644
index 000000000000..0ca462ffc56d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexContent.java
@@ -0,0 +1,65 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+public class ComplexContent
+ extends Node
+{
+ public ComplexContent (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.ComplexContent;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "complex content";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexType.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexType.java
new file mode 100644
index 000000000000..7ea0de9404d1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexType.java
@@ -0,0 +1,72 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'complexType' XML schema element. It specifies the
+ * structure of its children.
+ */
+public class ComplexType
+ extends Node
+{
+ public ComplexType (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(aParent, aName, aLocation);
+
+ assert(aName!=null);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.ComplexType;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "complex type "+GetName().GetDisplayName();
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexTypeReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexTypeReference.java
new file mode 100644
index 000000000000..28266a4a5219
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexTypeReference.java
@@ -0,0 +1,100 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class ComplexTypeReference
+ extends Node
+ implements INodeReference
+{
+ ComplexTypeReference (
+ final Node aParent,
+ final QualifiedName aReferencedTypeName,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maReferencedTypeName = aReferencedTypeName;
+ }
+
+
+
+
+ public ComplexType GetReferencedComplexType (final SchemaBase aSchema)
+ {
+ final Node aType = aSchema.GetTypeForName(maReferencedTypeName);
+ if (aType == null)
+ throw new RuntimeException();
+ else if (aType.GetNodeType() != NodeType.ComplexType)
+ throw new RuntimeException();
+ else
+ return (ComplexType)aType;
+ }
+
+
+
+
+
+ public QualifiedName GetReferencedTypeName ()
+ {
+ return maReferencedTypeName;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchema)
+ {
+ return GetReferencedComplexType(aSchema);
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.SimpleTypeReference;
+ }
+
+
+
+
+ private final QualifiedName maReferencedTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Element.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Element.java
new file mode 100644
index 000000000000..27c00fe6cf8b
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Element.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'element' XML schema element.
+ */
+public class Element
+ extends Node
+{
+ /** Create a new element that represents a transition to aTypeName when a
+ * start tag of aElementName is processed.
+ */
+ public Element (
+ final Node aParent,
+ final QualifiedName aElementName,
+ final QualifiedName aTypeName,
+ final Location aLocation)
+ {
+ super(aParent, aElementName, aLocation);
+ maElementName = aElementName;
+ maTypeName = aTypeName;
+ }
+
+
+
+
+ public QualifiedName GetElementName ()
+ {
+ return maElementName;
+ }
+
+
+
+
+ public QualifiedName GetTypeName ()
+ {
+ return maTypeName;
+ }
+
+
+
+
+ @Override
+ public int compareTo (final Node aOther)
+ {
+ if (aOther.GetNodeType() != NodeType.Element)
+ throw new RuntimeException("can not compare Element object to non-Element object");
+ else
+ return maElementName.compareTo(((Element)aOther).maElementName);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Element;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "element " + maElementName.GetDisplayName() +" -> " + maTypeName.GetDisplayName();
+ }
+
+
+
+
+ private final QualifiedName maElementName;
+ private final QualifiedName maTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ElementReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ElementReference.java
new file mode 100644
index 000000000000..48b2e7fa356f
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ElementReference.java
@@ -0,0 +1,106 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class ElementReference
+ extends Element
+ implements INodeReference
+{
+ public ElementReference (
+ final Node aParent,
+ final QualifiedName aReferencedElementName,
+ final Location aLocation)
+ {
+ super(aParent, null, null, aLocation);
+
+ maReferencedElementName = aReferencedElementName;
+ }
+
+
+
+
+ public QualifiedName GetReferencedElementName ()
+ {
+ return maReferencedElementName;
+ }
+
+
+
+
+ public Element GetReferencedElement (final SchemaBase aSchema)
+ {
+ final Element aElement = aSchema.TopLevelElements.Get(maReferencedElementName);
+ if (aElement == null)
+ throw new RuntimeException("can not find element "+maReferencedElementName.GetDisplayName());
+ return aElement;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchema)
+ {
+ return GetReferencedElement(aSchema);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.ElementReference;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "element reference to "+maReferencedElementName.GetDisplayName();
+ }
+
+
+
+
+ private final QualifiedName maReferencedElementName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Extension.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Extension.java
new file mode 100644
index 000000000000..749c608f6c27
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Extension.java
@@ -0,0 +1,160 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Representation of the 'extension' XML schema element.
+ * It extends a complex base type.
+ */
+public class Extension
+ extends Node
+ implements INodeReference
+{
+ public Extension (
+ final Node aParent,
+ final QualifiedName aBaseTypeName,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maBaseTypeName = aBaseTypeName;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.Extension;
+ }
+
+
+
+
+ public QualifiedName GetBaseTypeName()
+ {
+ return maBaseTypeName;
+ }
+
+
+
+
+ public INode GetBaseType (final SchemaBase aSchema)
+ {
+ return aSchema.GetTypeForName(maBaseTypeName);
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchema)
+ {
+ return GetBaseType(aSchema);
+ }
+
+
+
+
+ public Vector<INode> GetTypeNodes (final SchemaBase aSchemaBase)
+ {
+ final Vector<INode> aNodes = new Vector<>();
+
+ AddNodes(aSchemaBase.GetTypeForName(maBaseTypeName), aNodes, aSchemaBase);
+ for (final INode aChild : GetChildren())
+ AddNodes(aChild, aNodes, aSchemaBase);
+
+ return aNodes;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "extension of base type "+maBaseTypeName.GetDisplayName();
+ }
+
+
+
+
+ private void AddNodes (
+ final INode aParent,
+ final Vector<INode> aNodes,
+ final SchemaBase aSchemaBase)
+ {
+ INode aNode = aParent;
+ while (true)
+ {
+ switch (aNode.GetNodeType())
+ {
+ case Extension:
+ aNode = ((Extension)aNode).GetBaseType(aSchemaBase);
+ break;
+
+ case ComplexContent:
+ case SimpleContent:
+ case ComplexType:
+ switch(aNode.GetChildCount())
+ {
+ case 0:
+ return;
+ case 1:
+ aNode = aNode.GetOnlyChild();
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ break;
+
+ default:
+ aNodes.add(aNode);
+ return;
+ }
+ }
+ }
+
+
+
+
+ public QualifiedName maBaseTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Group.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Group.java
new file mode 100644
index 000000000000..4358c20849a5
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Group.java
@@ -0,0 +1,70 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Represents the 'group' XML schema element.
+ * The concepts of groups are similar to macros.
+ */
+public class Group
+ extends Node
+{
+ public Group (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(aParent, aName, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Group;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "group "+GetName().GetDisplayName();
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/GroupReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/GroupReference.java
new file mode 100644
index 000000000000..048308ca9940
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/GroupReference.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class GroupReference
+ extends Node
+ implements INodeReference
+{
+ public GroupReference (
+ final Node aParent,
+ final QualifiedName aReferencedGroupName,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+
+ maReferencedGroupName = aReferencedGroupName;
+ }
+
+
+
+
+ public QualifiedName GetReferencedGroupName ()
+ {
+ return maReferencedGroupName;
+ }
+
+
+
+
+ public Group GetReferencedGroup (final SchemaBase aSchemaBase)
+ {
+ final Node aType = aSchemaBase.GetTypeForName(maReferencedGroupName);
+ if (aType == null)
+ throw new RuntimeException("there is no type named '"+maReferencedGroupName+"' in the schema");
+ else if (aType.GetNodeType()!=NodeType.Group)
+ throw new RuntimeException("name '"+maReferencedGroupName+"' references a "+aType.GetNodeType()+" not a group");
+ else
+ return (Group)aType;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchemaBase)
+ {
+ return GetReferencedGroup(aSchemaBase);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.GroupReference;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "group reference to "+maReferencedGroupName.GetDisplayName();
+ }
+
+
+
+
+ private final QualifiedName maReferencedGroupName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/OccurrenceIndicator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/OccurrenceIndicator.java
new file mode 100644
index 000000000000..dcc41bfbb7ce
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/OccurrenceIndicator.java
@@ -0,0 +1,152 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** An occurrence indicator is based on a minimum and a maximum value.
+ * The minimum value is 0 or larger. If it is 0 then the child node is optional.
+ * The maximum value is at least as large as the minimum value.
+ * It can be 'unbounded' in which case the child node can appear any number of times.
+ * 'Unbounded' is internally stored as -1.
+ *
+ * An OccurrenceIndicator represents the minOccur and maxOccur attributes of
+ * XML schema elements.
+ *
+ * There is usually exactly one child.
+ */
+public class OccurrenceIndicator
+ extends Node
+{
+ public static int unbounded = -1;
+
+ public OccurrenceIndicator (
+ final Node aParent,
+ final String sMinimum,
+ final String sMaximum,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+
+ mnMinimum = ParseValue(sMinimum);
+ mnMaximum = ParseValue(sMaximum);
+
+ assert(mnMinimum>=0);
+ assert(mnMaximum==unbounded || mnMaximum>=mnMinimum);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.OccurrenceIndicator;
+ }
+
+
+
+
+ /** Return a string version of the minimum value for textual display.
+ */
+ public String GetDisplayMinimum ()
+ {
+ return Integer.toString(mnMinimum);
+ }
+
+
+
+
+ /** Return a string version of the maximum value for textual display.
+ */
+ public String GetDisplayMaximum ()
+ {
+ if (mnMaximum == unbounded)
+ return "unbounded";
+ else
+ return Integer.toString(mnMaximum);
+ }
+
+
+
+
+ public int GetMinimum ()
+ {
+ return mnMinimum;
+ }
+
+
+
+
+ public int GetMaximum ()
+ {
+ return mnMaximum;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("occurrence %s to %s",
+ GetDisplayMinimum(),
+ GetDisplayMaximum());
+ }
+
+
+
+
+ private static int ParseValue (final String sValue)
+ {
+ if (sValue == null)
+ {
+ // Missing values default to 1.
+ return 1;
+ }
+ else
+ switch (sValue)
+ {
+ case "0" : return 0;
+ case "1" : return 1;
+ case "unbounded" : return unbounded;
+ default: return Integer.parseInt(sValue);
+ }
+ }
+
+
+
+ private final int mnMinimum;
+ private final int mnMaximum;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Sequence.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Sequence.java
new file mode 100644
index 000000000000..da01a8c15e28
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Sequence.java
@@ -0,0 +1,73 @@
+/**************************************************************
+*
+* 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.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of a 'sequence' XML schema element.
+ * It defines an order on its children.
+ */
+ public class Sequence
+ extends Node
+{
+ public Sequence (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(aParent, aName, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Sequence;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ if (GetName() != null)
+ return "sequence "+GetName().GetDisplayName();
+ else
+ return "sequence";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/CopyVisitor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/CopyVisitor.java
new file mode 100644
index 000000000000..4fb84c909bf1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/CopyVisitor.java
@@ -0,0 +1,112 @@
+/**************************************************************
+*
+* 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.model.optimize;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+/** This visitor is called to copy the used types from the source to the target
+ * schema base.
+ */
+public class CopyVisitor
+ extends NodeVisitorAdapter
+{
+ CopyVisitor (
+ final SchemaBase aSourceSchemaBase,
+ final SchemaBase aTargetSchemaBase)
+ {
+ maSourceSchemaBase = aSourceSchemaBase;
+ maTargetSchemaBase = aTargetSchemaBase;
+ }
+
+
+
+
+ @Override public void Visit (final ComplexType aComplexType)
+ {
+ maTargetSchemaBase.ComplexTypes.Add(aComplexType);
+ }
+
+ @Override public void Visit (final GroupReference aGroupReference)
+ {
+ maTargetSchemaBase.Groups.Add(
+ aGroupReference.GetReferencedGroup(maSourceSchemaBase));
+ }
+
+ @Override public void Visit (final SimpleType aSimpleType)
+ {
+ maTargetSchemaBase.SimpleTypes.Add(aSimpleType);
+ }
+
+ @Override public void Visit (final AttributeReference aAttributeReference)
+ {
+ maTargetSchemaBase.Attributes.Add(
+ aAttributeReference.GetReferencedAttribute(maSourceSchemaBase));
+ }
+
+ @Override public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ maTargetSchemaBase.AttributeGroups.Add(
+ aAttributeGroupReference.GetReferencedAttributeGroup(maSourceSchemaBase));
+ }
+
+ @Override public void Default (final INode aNode)
+ {
+ switch(aNode.GetNodeType())
+ {
+ case All:
+ case Any:
+ case Attribute:
+ case AttributeGroup:
+ case BuiltIn:
+ case Choice:
+ case ComplexContent:
+ case Element:
+ case ElementReference:
+ case Extension:
+ case Group:
+ case List:
+ case OccurrenceIndicator:
+ case Restriction:
+ case Sequence:
+ case SimpleContent:
+ case SimpleTypeReference:
+ case Union:
+ break;
+
+ default:
+ throw new RuntimeException("don't know how to copy "+aNode.toString());
+ }
+ }
+
+
+
+
+ private final SchemaBase maSourceSchemaBase;
+ private final SchemaBase maTargetSchemaBase;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/RequestVisitor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/RequestVisitor.java
new file mode 100644
index 000000000000..20aa02dd1752
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/RequestVisitor.java
@@ -0,0 +1,128 @@
+/**************************************************************
+*
+* 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.model.optimize;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+
+/** A visitor that is called for all nodes of a complex or simple type to mark
+ * the referenced types as being used.
+ */
+public class RequestVisitor
+ extends NodeVisitorAdapter
+{
+ RequestVisitor (
+ final SchemaBase aSourceSchema,
+ final SchemaOptimizer aOptimizer)
+ {
+ maSourceSchemaBase = aSourceSchema;
+ maSchemaOptimizer = aOptimizer;
+ }
+
+
+ @Override public void Visit (final Attribute aAttribute)
+ {
+ maSchemaOptimizer.RequestType(aAttribute.GetTypeName());
+ }
+
+ @Override public void Visit (final AttributeReference aAttributeReference)
+ {
+ maSchemaOptimizer.RequestType(aAttributeReference.GetReferencedName());
+ }
+
+ @Override public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ maSchemaOptimizer.RequestType(aAttributeGroupReference.GetReferencedName());
+ }
+
+ @Override public void Visit (final Element aElement)
+ {
+ maSchemaOptimizer.RequestType(aElement.GetTypeName());
+ }
+
+ @Override public void Visit (final Extension aExtension)
+ {
+ maSchemaOptimizer.RequestType(aExtension.GetBaseTypeName());
+ }
+
+ @Override public void Visit (final GroupReference aReference)
+ {
+ maSchemaOptimizer.RequestType(aReference.GetReferencedGroup(maSourceSchemaBase));
+ }
+
+ @Override public void Visit (final List aList)
+ {
+ maSchemaOptimizer.RequestType(aList.GetItemType());
+ }
+
+ @Override public void Visit (final Restriction aRestriction)
+ {
+ maSchemaOptimizer.RequestType(aRestriction.GetBaseType());
+ }
+
+ @Override public void Visit (final SimpleTypeReference aReference)
+ {
+ maSchemaOptimizer.RequestType(aReference.GetReferencedSimpleType(maSourceSchemaBase));
+ }
+
+ @Override public void Default (final INode aNode)
+ {
+ switch (aNode.GetNodeType())
+ {
+ case All:
+ case Any:
+ case AttributeGroup:
+ case BuiltIn:
+ case Choice:
+ case ComplexContent:
+ case ComplexType:
+ case ElementReference:
+ case Group:
+ case List:
+ case OccurrenceIndicator:
+ case Sequence:
+ case SimpleContent:
+ case SimpleType:
+ case Union:
+ break;
+
+ default:
+ throw new RuntimeException(
+ String.format("don't know how to request %s which was defined at %s",
+ aNode.toString(),
+ aNode.GetLocation()));
+ }
+ }
+
+ private final SchemaBase maSourceSchemaBase;
+ private final SchemaOptimizer maSchemaOptimizer;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/SchemaOptimizer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/SchemaOptimizer.java
new file mode 100644
index 000000000000..808f15dc1642
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/SchemaOptimizer.java
@@ -0,0 +1,140 @@
+/**************************************************************
+*
+* 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.model.optimize;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+
+import org.apache.openoffice.ooxml.schema.iterator.AttributeNodeIterator;
+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.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Optimize the given schema base by creating a new one and adding only those
+ * complex types, simple types, groups, attributes and attribute groups, that
+ * are really used, i.e. used by one of the top level elements or by a type or
+ * group that is in use.
+ */
+public class SchemaOptimizer
+{
+ public SchemaOptimizer (
+ final SchemaBase aOriginalSchemaBase)
+ {
+ maOriginalSchemaBase = aOriginalSchemaBase;
+ maOptimizedSchemaBase = new SchemaBase();
+ maTodoList = new LinkedList<>();
+ maProcessedTypes = new HashSet<>();
+ }
+
+
+
+
+ public SchemaBase Run ()
+ {
+ // Seed the work list with the top-level elements.
+ for (final Element aElement : maOriginalSchemaBase.TopLevelElements.GetUnsorted())
+ {
+ maOptimizedSchemaBase.TopLevelElements.Add(aElement);
+ RequestType(aElement.GetTypeName());
+ }
+
+ final INodeVisitor aCopyVisitor = new CopyVisitor(
+ maOriginalSchemaBase,
+ maOptimizedSchemaBase);
+ final INodeVisitor aRequestVisitor = new RequestVisitor(
+ maOriginalSchemaBase,
+ this);
+
+ while ( ! maTodoList.isEmpty())
+ {
+ final INode aNode = maTodoList.poll();
+
+ // Iterate over all child nodes and attributes.
+ for (final INode aChild : new DereferencingNodeIterator(aNode, maOriginalSchemaBase, true))
+ {
+ aChild.AcceptVisitor(aCopyVisitor);
+ aChild.AcceptVisitor(aRequestVisitor);
+ for (final INode aAttribute : aChild.GetAttributes())
+ aAttribute.AcceptVisitor(aCopyVisitor);
+ for (final INode aAttribute : new AttributeNodeIterator(aChild, maOriginalSchemaBase))
+ aAttribute.AcceptVisitor(aRequestVisitor);
+ }
+
+ // Request used namespaces.
+ final QualifiedName aName = aNode.GetName();
+ if (aName != null)
+ maOptimizedSchemaBase.Namespaces.ProvideNamespace(aName.GetNamespaceURI(), aName.GetNamespacePrefix());
+ }
+
+ /*
+ System.out.printf("%d original attributes\n", maOriginalSchemaBase.Attributes.GetCount());
+ for (final Attribute aAttribute : maOriginalSchemaBase.Attributes.GetUnsorted())
+ System.out.printf("%s\n", aAttribute);
+ System.out.printf("%d optimized attributes\n", maOptimizedSchemaBase.Attributes.GetCount());
+ for (final Attribute aAttribute : maOptimizedSchemaBase.Attributes.GetUnsorted())
+ System.out.printf("%s\n", aAttribute);
+ */
+
+ return maOptimizedSchemaBase;
+ }
+
+
+
+
+ void RequestType (final QualifiedName aName)
+ {
+ final Node aNode = maOriginalSchemaBase.GetTypeForName(aName);
+ if (aNode == null)
+ throw new RuntimeException("there is no type named '"+aName+"' in the schema");
+ else
+ RequestType(aNode);
+ }
+
+
+
+
+ void RequestType (final INode aNode)
+ {
+ if (aNode.GetNodeType() == NodeType.SimpleTypeReference)
+ System.out.println(aNode);
+ if ( ! maProcessedTypes.contains(aNode))
+ {
+ maProcessedTypes.add(aNode);
+ maTodoList.add(aNode);
+ }
+ }
+
+
+
+
+ private final SchemaBase maOriginalSchemaBase;
+ private final SchemaBase maOptimizedSchemaBase;
+ private final Queue<INode> maTodoList;
+ private final Set<INode> maProcessedTypes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/NamespaceMap.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/NamespaceMap.java
new file mode 100644
index 000000000000..d3cfdafd8a0b
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/NamespaceMap.java
@@ -0,0 +1,178 @@
+/**************************************************************
+*
+* 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.model.schema;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/** Map between namespace prefixes and URIs.
+ * While namespace URIs can have different prefixes in different schemas,
+ * we will use only one prefix in the OOXML parser. This class
+ * provides these global prefixes.
+ */
+public class NamespaceMap
+ implements Iterable<Entry<String, String>>
+{
+ public NamespaceMap ()
+ {
+ maURIToPrefixMap = new HashMap<>(maPredefinedURIToPrefixMap);
+
+ // Predefine namespace prefixes.
+ // If possible then use the ones already in use in the schema files or documents written by MS Office,
+ // appended with a 06 or 12 for the ECMA-376 standards of 2006 (1st edition) or 2012 (4th edition).
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/drawingml/2006/main", "a06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/main", "a12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", "wp06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/wordprocessingDrawing", "wp12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/wordprocessingml/main", "w12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/drawingml/2006/picture", "dpct06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/picture", "dpct12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/officeDocument/2006/math", "m06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/officeDocument/math", "m12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/officeDocument/relationships", "r12");
+
+ // Invent prefixes that are not in use.
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/spreadsheetml/2006/main", "s06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/spreadsheetml/main", "s12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/presentationml/2006/main", "p06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/presentationml/main", "p12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/schemaLibrary/2006/main", "sl06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/schemaLibrary/main", "sl12");
+
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/diagram", "dd12");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/chart", "dc12");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/lockedCanvas", "dlc12");
+ }
+
+
+
+
+ public void ProvideNamespace (
+ final String sNamespaceURI,
+ final String sDefaultPrefix)
+ {
+ if ( ! maURIToPrefixMap.containsKey(sNamespaceURI))
+ {
+ final String sPrefix;
+ // Check if we can use the given prefix.
+ if (sDefaultPrefix==null || IsPrefixUsed(sDefaultPrefix))
+ {
+ // Prefix is already used. We have to create a new and unique one.
+ String sCandidate = null;
+ for (int nIndex=0; nIndex<=26; ++nIndex)
+ {
+ if (nIndex == 26)
+ throw new RuntimeException("can not invent more than 26 namespace names");
+ sCandidate= new String(new byte[]{(byte)('A'+nIndex)});
+ if ( ! maURIToPrefixMap.containsKey(sCandidate))
+ break;
+ }
+ sPrefix = sCandidate;
+ }
+ else
+ {
+ // Use the given prefix.
+ sPrefix = sDefaultPrefix;
+ }
+
+ maURIToPrefixMap.put(sNamespaceURI, sPrefix);
+ }
+ }
+
+
+
+
+ public String GetNamespacePrefix (final String sURI)
+ {
+ return maURIToPrefixMap.get(sURI);
+ }
+
+
+
+
+ public Iterator<Entry<String,String>> iterator ()
+ {
+ return maURIToPrefixMap.entrySet().iterator();
+ }
+
+
+
+
+ public Object GetCount()
+ {
+ return maURIToPrefixMap.size();
+ }
+
+
+
+
+ /** Return all namespace entries sorted on the prefix.
+ */
+ public Iterable<Entry<String,String>> GetSorted ()
+ {
+ final Map<String,Entry<String,String>> aSortedEntries = new TreeMap<>();
+ for (final Entry<String,String> aEntry : maURIToPrefixMap.entrySet())
+ if (aEntry.getValue() == null)
+ aSortedEntries.put("", aEntry);
+ else
+ aSortedEntries.put(aEntry.getValue(), aEntry);
+ return aSortedEntries.values();
+ }
+
+
+
+
+ private boolean IsPrefixUsed (final String sPrefix)
+ {
+ for (final String sUsedPrefix : maURIToPrefixMap.values())
+ {
+ if (sUsedPrefix == null)
+ continue;
+ if (sUsedPrefix.equals(sPrefix))
+ return true;
+ }
+ return false;
+ }
+
+
+
+
+ private final Map<String,String> maURIToPrefixMap;
+ private final static Map<String,String> maPredefinedURIToPrefixMap;
+ static
+ {
+ maPredefinedURIToPrefixMap = new HashMap<>();
+ maPredefinedURIToPrefixMap.put("http://www.w3.org/2001/XMLSchema", "xsd");
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/Schema.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/Schema.java
new file mode 100644
index 000000000000..47c511ef4e12
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/Schema.java
@@ -0,0 +1,107 @@
+/**************************************************************
+*
+* 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.model.schema;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+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.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+/** Front end of a shared SchemaBase object of a single master schema file (such
+ * as wml.xsd).
+ * Most important member is the TopLevelElements list of top level elements,
+ * which are unique to each master schema.
+ */
+public class Schema
+{
+ public Schema (
+ final String sShortName,
+ final SchemaBase aBase)
+ {
+ msShortName = sShortName;
+ TopLevelElements = new TypeContainer<>();
+
+ Namespaces = aBase.Namespaces;
+ ComplexTypes = aBase.ComplexTypes;
+ SimpleTypes = aBase.SimpleTypes;
+ Groups = aBase.Groups;
+ AttributeGroups = aBase.AttributeGroups;
+ Attributes = aBase.Attributes;
+ }
+
+
+
+
+ public Node GetTypeForName (final QualifiedName aName)
+ {
+ final String sTypeName = aName.GetDisplayName();
+
+ if (ComplexTypes.Contains(sTypeName))
+ return ComplexTypes.Get(sTypeName);
+ else if (SimpleTypes.Contains(sTypeName))
+ return SimpleTypes.Get(sTypeName);
+ else if (Groups.Contains(sTypeName))
+ return Groups.Get(sTypeName);
+ else if (TopLevelElements.Contains(sTypeName))
+ return TopLevelElements.Get(sTypeName);
+ else
+ return null;
+ }
+
+
+
+
+ public String GetShortName ()
+ {
+ return msShortName;
+ }
+
+
+
+
+ public Schema GetOptimizedSchema (final SchemaBase aSchemaBase)
+ {
+ final Schema aOptimizedSchema = new Schema(msShortName, aSchemaBase);
+ for (final Element aElement : TopLevelElements.GetUnsorted())
+ {
+ aOptimizedSchema.TopLevelElements.Add(aElement);
+ }
+
+ return aOptimizedSchema;
+ }
+
+
+
+
+ private final String msShortName;
+ public final TypeContainer<Element> TopLevelElements;
+ public final NamespaceMap Namespaces;
+ public final TypeContainer<ComplexType> ComplexTypes;
+ public final TypeContainer<SimpleType> SimpleTypes;
+ public final TypeContainer<Group> Groups;
+ public final TypeContainer<AttributeGroup> AttributeGroups;
+ public final TypeContainer<Attribute> Attributes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/SchemaBase.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/SchemaBase.java
new file mode 100644
index 000000000000..8b456acea7f4
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/SchemaBase.java
@@ -0,0 +1,121 @@
+/**************************************************************
+*
+* 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.model.schema;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+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.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.optimize.SchemaOptimizer;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+
+/** Container of elements, complex types, simple types, etc for a set of
+ * master schema files and the included and imported secondary schema files.
+ *
+ * See Schema objects for the set of top level elements that are unique to
+ * each master schema file.
+ */
+public class SchemaBase
+{
+ public SchemaBase ()
+ {
+ Namespaces = new NamespaceMap();
+ TopLevelElements = new TypeContainer<>();
+ ComplexTypes = new TypeContainer<>();
+ SimpleTypes = new TypeContainer<>();
+ Groups = new TypeContainer<>();
+ AttributeGroups = new TypeContainer<>();
+ Attributes = new TypeContainer<>();
+ AttributeValueToIdMap = new HashMap<>();
+
+ // Initialize the list of simple types with all known built ins (
+ // these are implicitly defined).
+ for (final BuiltIn aType : BuiltIn.GetTypes())
+ SimpleTypes.Add(aType);
+ }
+
+
+
+
+ public Node GetTypeForName (final QualifiedName aName)
+ {
+ final String sTypeName = aName.GetDisplayName();
+
+ if (ComplexTypes.Contains(sTypeName))
+ return ComplexTypes.Get(sTypeName);
+ else if (SimpleTypes.Contains(sTypeName))
+ return SimpleTypes.Get(sTypeName);
+ else if (Groups.Contains(sTypeName))
+ return Groups.Get(sTypeName);
+ else if (Attributes.Contains(sTypeName))
+ return Attributes.Get(sTypeName);
+ else if (AttributeGroups.Contains(sTypeName))
+ return AttributeGroups.Get(sTypeName);
+ else
+ return null;
+ }
+
+
+
+
+ public Node GetSimpleTypeForName (final QualifiedName aName)
+ {
+ final String sTypeName = aName.GetDisplayName();
+
+ if (SimpleTypes.Contains(sTypeName))
+ return SimpleTypes.Get(aName.GetDisplayName());
+ else
+ return null;
+ }
+
+
+
+
+ /** Create a new schema object that contains only the used types, i.e.
+ * types that are reachable via element transitions, starting with the
+ * top level elements.
+ */
+ public SchemaBase GetOptimizedSchema (final Iterable<Schema> aTopLevelSchemas)
+ {
+ return new SchemaOptimizer(this).Run();
+ }
+
+
+
+
+ public final NamespaceMap Namespaces;
+ public final TypeContainer<Element> TopLevelElements;
+ public final TypeContainer<ComplexType> ComplexTypes;
+ public final TypeContainer<SimpleType> SimpleTypes;
+ public final TypeContainer<Group> Groups;
+ public final TypeContainer<AttributeGroup> AttributeGroups;
+ public final TypeContainer<Attribute> Attributes;
+ public final Map<String,Integer> AttributeValueToIdMap;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/TypeContainer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/TypeContainer.java
new file mode 100644
index 000000000000..1855469fbba9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/TypeContainer.java
@@ -0,0 +1,100 @@
+/**************************************************************
+*
+* 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.model.schema;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+public class TypeContainer<T extends Node>
+{
+ TypeContainer ()
+ {
+ maTypes = new HashMap<>();
+ }
+
+
+
+
+ public void Add (final T aType)
+ {
+ maTypes.put(aType.GetName().GetDisplayName(), aType);
+ }
+
+
+
+
+ public T Get (final QualifiedName aName)
+ {
+ return maTypes.get(aName.GetDisplayName());
+ }
+
+
+
+
+ public T Get (final String sPrefixedName)
+ {
+ return maTypes.get(sPrefixedName);
+ }
+
+
+
+
+ public boolean Contains (final String sPrefixedName)
+ {
+ return maTypes.containsKey(sPrefixedName);
+ }
+
+
+
+
+ public int GetCount ()
+ {
+ return maTypes.size();
+ }
+
+
+
+
+ public Iterable<T> GetUnsorted ()
+ {
+ return maTypes.values();
+ }
+
+
+
+
+ public Iterable<T> GetSorted ()
+ {
+ final Set<T> aSortedItems = new TreeSet<T>(maTypes.values());
+ return aSortedItems;
+ }
+
+
+
+
+ Map<String,T> maTypes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltIn.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltIn.java
new file mode 100644
index 000000000000..72ae7fc278a1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltIn.java
@@ -0,0 +1,103 @@
+/**************************************************************
+*
+* 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.model.simple;
+
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of built in types.
+ */
+public class BuiltIn
+ extends SimpleType
+{
+ public static Vector<BuiltIn> GetTypes ()
+ {
+ final Vector<BuiltIn> aTypes = new Vector<>();
+ for (final BuiltInType eType : BuiltInType.values())
+ aTypes.add(new BuiltIn(eType));
+ return aTypes;
+ }
+
+
+
+
+ protected BuiltIn (
+ final BuiltInType eType)
+ {
+ super(null, eType.GetQualifiedName(), new Location());
+ meType = eType;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.BuiltIn;
+ }
+
+
+
+
+ public BuiltInType GetBuiltInType ()
+ {
+ return meType;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "builtin "+GetName().GetDisplayName();
+ }
+
+
+
+
+ private final BuiltInType meType;
+
+
+
+
+ public static Node GetForName(QualifiedName aName)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltInType.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltInType.java
new file mode 100644
index 000000000000..4befae2ee7f7
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltInType.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* 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.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.parser.XsdNamespace;
+
+public enum BuiltInType
+{
+ AnyURI,
+ Base64Binary,
+ Boolean,
+ Byte,
+ Float,
+ DateTime,
+ Double,
+ HexBinary,
+ ID,
+ Int,
+ Integer,
+ Long,
+ NcName,
+ Short,
+ String,
+ Token,
+ UnsignedByte,
+ UnsignedInt,
+ UnsignedLong,
+ UnsignedShort;
+
+ public static BuiltInType GetForName (final QualifiedName aName)
+ {
+ assert(aName.GetNamespacePrefix().equals(XsdNamespace.Prefix));
+ switch(aName.GetLocalPart())
+ {
+ case "anyURI": return AnyURI;
+ case "base64Binary": return Base64Binary;
+ case "boolean": return Boolean;
+ case "byte": return Byte;
+ case "dateTime": return DateTime;
+ case "double": return Double;
+ case "float": return Float;
+ case "hexBinary": return HexBinary;
+ case "ID": return ID;
+ case "int" : return Int;
+ case "integer": return Integer;
+ case "long": return Long;
+ case "NCName": return NcName;
+ case "short": return Short;
+ case "string": return String;
+ case "token": return Token;
+ case "unsignedByte": return UnsignedByte;
+ case "unsignedInt": return UnsignedInt;
+ case "unsignedLong": return UnsignedLong;
+ case "unsignedShort": return UnsignedShort;
+ default: throw new RuntimeException("there is no builtin type named "+aName.GetDisplayName());
+ }
+ }
+
+ public QualifiedName GetQualifiedName ()
+ {
+ final String sTypeName;
+ switch(this)
+ {
+ case AnyURI: sTypeName = "anyURI"; break;
+ case Base64Binary: sTypeName = "base64Binary"; break;
+ case Boolean: sTypeName = "boolean"; break;
+ case Byte: sTypeName = "byte"; break;
+ case Double: sTypeName = "double"; break;
+ case DateTime: sTypeName = "dateTime"; break;
+ case Float: sTypeName = "float"; break;
+ case HexBinary: sTypeName = "hexBinary"; break;
+ case ID: sTypeName = "ID"; break;
+ case Int: sTypeName = "int"; break;
+ case Integer: sTypeName = "integer"; break;
+ case Long: sTypeName = "long"; break;
+ case NcName: sTypeName = "NCName"; break;
+ case Short: sTypeName = "short"; break;
+ case String: sTypeName = "string"; break;
+ case Token: sTypeName = "token"; break;
+ case UnsignedByte: sTypeName = "unsignedByte"; break;
+ case UnsignedInt: sTypeName = "unsignedInt"; break;
+ case UnsignedLong: sTypeName = "unsignedLong"; break;
+ case UnsignedShort: sTypeName = "unsignedShort"; break;
+ default:
+ throw new RuntimeException();
+ }
+ return new QualifiedName(XsdNamespace.URI, XsdNamespace.Prefix, sTypeName);
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/List.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/List.java
new file mode 100644
index 000000000000..cac0a43e2591
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/List.java
@@ -0,0 +1,84 @@
+/**************************************************************
+*
+* 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.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'list' XML schema element.
+ * It is similar to an array of objects that are all of the same simple type.
+ */
+public class List
+ extends Node
+{
+ public List (
+ final Node aParent,
+ final QualifiedName aItemType,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maItemType = aItemType;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.List;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ public QualifiedName GetItemType ()
+ {
+ return maItemType;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "list of "+maItemType.GetDisplayName()+" items";
+ }
+
+
+
+
+ private final QualifiedName maItemType;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Restriction.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Restriction.java
new file mode 100644
index 000000000000..8ee71d02f0c2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Restriction.java
@@ -0,0 +1,337 @@
+/**************************************************************
+*
+* 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.model.simple;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'restriction' XML schema element.
+ * It defines constraints on a another simple type.
+ * Examples for such restrictions are minimum and maximum values
+ * (inclusive or exclusive), patterns or length constraints of strings,
+ * sets of valid values.
+ */
+public class Restriction
+ extends Node
+{
+ public final static int MinInclusiveBit = 0x0001;
+ public final static int MinExclusiveBit = 0x0002;
+ public final static int MaxInclusiveBit = 0x0004;
+ public final static int MaxExclusiveBit = 0x0008;
+ public final static int LengthBit = 0x0010;
+ public final static int MinLengthBit = 0x0020;
+ public final static int MaxLengthBit = 0x0040;
+ public final static int PatternBit = 0x0080;
+ public final static int EnumerationBit = 0x0100;
+
+ public Restriction (
+ final Node aParent,
+ final QualifiedName aBaseType,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maBaseType = aBaseType;
+ maEnumerations = new TreeSet<>();
+ mnFeatures = 0;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.Restriction;
+ }
+
+
+
+
+ public QualifiedName GetBaseType ()
+ {
+ return maBaseType;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ final StringBuffer aBuffer = new StringBuffer("restriction based on ");
+ aBuffer.append(maBaseType.GetDisplayName());
+
+ if (msMinInclusive != null)
+ {
+ aBuffer.append(",minInclusive=");
+ aBuffer.append(msMinInclusive);
+ }
+ if (msMinExclusive != null)
+ {
+ aBuffer.append(",minExclusive=");
+ aBuffer.append(msMinExclusive);
+ }
+ if (msMaxInclusive != null)
+ {
+ aBuffer.append(",maxInclusive=");
+ aBuffer.append(msMaxInclusive);
+ }
+ if (msMaxExclusive != null)
+ {
+ aBuffer.append(",maxExclusive=");
+ aBuffer.append(msMaxExclusive);
+ }
+ if (HasFeature(LengthBit))
+ {
+ aBuffer.append(",length=");
+ aBuffer.append(mnLength);
+ }
+ if (HasFeature(MinLengthBit))
+ {
+ aBuffer.append(",minLength=");
+ aBuffer.append(mnMinLength);
+ }
+ if (HasFeature(MaxLengthBit))
+ {
+ aBuffer.append(",maxLength=");
+ aBuffer.append(mnMaxLength);
+ }
+ if (msPattern != null)
+ {
+ aBuffer.append(",pattern=\"");
+ aBuffer.append(msPattern);
+ aBuffer.append('"');
+ }
+ if ( ! maEnumerations.isEmpty())
+ {
+ aBuffer.append(",enumerations");
+ aBuffer.append(maEnumerations);
+ }
+ return aBuffer.toString();
+ }
+
+
+
+ public void AddEnumeration (final String sValue)
+ {
+ maEnumerations.add(sValue);
+ mnFeatures |= EnumerationBit;
+ }
+
+
+
+
+ public void SetMinInclusive (final String sValue)
+ {
+ msMinInclusive = sValue;
+ assert( ! HasFeature(MinExclusiveBit));
+ mnFeatures |= MinInclusiveBit;
+ }
+
+
+
+
+ public void SetMinExclusive (final String sValue)
+ {
+ msMinExclusive = sValue;
+ assert( ! HasFeature(MinInclusiveBit));
+ mnFeatures |= MinExclusiveBit;
+ }
+
+
+
+
+ public void SetMaxInclusive (final String sValue)
+ {
+ msMaxInclusive = sValue;
+ assert( ! HasFeature(MaxExclusiveBit));
+ mnFeatures |= MaxInclusiveBit;
+ }
+
+
+
+
+ public void SetMaxExclusive (final String sValue)
+ {
+ msMaxExclusive = sValue;
+ assert( ! HasFeature(MaxInclusiveBit));
+ mnFeatures |= MaxExclusiveBit;
+ }
+
+
+
+
+ public void SetLength (final String sValue)
+ {
+ mnLength = Integer.parseInt(sValue);
+ assert( ! HasFeature(MinLengthBit|MaxLengthBit));
+ mnFeatures |= LengthBit;
+ }
+
+
+
+
+ public void SetMinLength (final String sValue)
+ {
+ mnMinLength = Integer.parseInt(sValue);
+ assert( ! HasFeature(LengthBit));
+ mnFeatures |= MinLengthBit;
+ }
+
+
+
+
+ public void SetMaxLength (final String sValue)
+ {
+ mnMaxLength = Integer.parseInt(sValue);
+ assert( ! HasFeature(LengthBit));
+ mnFeatures |= MaxLengthBit;
+ }
+
+
+
+
+ public void SetPattern (final String sValue)
+ {
+ msPattern = sValue;
+ mnFeatures |= PatternBit;
+ }
+
+
+
+
+ public String GetMinInclusive ()
+ {
+ return msMinInclusive;
+ }
+
+
+
+
+ public String GetMinExclusive ()
+ {
+ return msMinExclusive;
+ }
+
+
+
+
+ public String GetMaxInclusive ()
+ {
+ return msMaxInclusive;
+ }
+
+
+
+
+ public String GetMaxExclusive ()
+ {
+ return msMaxExclusive;
+ }
+
+
+
+
+ public Set<String> GetEnumeration()
+ {
+ return maEnumerations;
+ }
+
+
+
+
+ public int GetLength()
+ {
+ return mnLength;
+ }
+
+
+
+
+ public int GetMinimumLength()
+ {
+ return mnMinLength;
+ }
+
+
+
+
+ public int GetMaximumLength()
+ {
+ return mnMaxLength;
+ }
+
+
+
+
+
+ public String GetPattern()
+ {
+ return msPattern;
+ }
+
+
+
+
+ public int GetFeatureBits ()
+ {
+ return mnFeatures;
+ }
+
+
+
+
+ public boolean HasFeature (final int nBitMask)
+ {
+ return (mnFeatures & nBitMask) != 0;
+ }
+
+
+
+
+ private final QualifiedName maBaseType;
+ private final Set<String> maEnumerations;
+ private String msMinInclusive;
+ private String msMinExclusive;
+ private String msMaxInclusive;
+ private String msMaxExclusive;
+ private int mnLength;
+ private int mnMinLength;
+ private int mnMaxLength;
+ private String msPattern;
+ private int mnFeatures;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleContent.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleContent.java
new file mode 100644
index 000000000000..332df9c2b99a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleContent.java
@@ -0,0 +1,65 @@
+/**************************************************************
+*
+* 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.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+public class SimpleContent
+ extends Node
+{
+ public SimpleContent (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.SimpleContent;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "simple content";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleType.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleType.java
new file mode 100644
index 000000000000..52366fb9c614
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleType.java
@@ -0,0 +1,102 @@
+/**************************************************************
+*
+* 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.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'simpleType' XML schema element.
+ * Simple types are used for attributes or the text of elements.
+ */
+public class SimpleType
+ extends Node
+{
+ public SimpleType (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(aParent, aName, aLocation);
+ maFinalValues = null;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.SimpleType;
+ }
+
+
+
+
+ public void SetFinal (final String[] aFinalValues)
+ {
+ maFinalValues = aFinalValues;
+ }
+
+
+
+
+ public boolean IsFinal (final String sCatgery)
+ {
+ if (maFinalValues != null)
+ {
+ for (final String sFinal : maFinalValues)
+ {
+ if (sFinal.equals(sCatgery))
+ return true;
+ else if (sFinal.equals("#all"))
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "simple type "+GetName().GetDisplayName();
+ }
+
+
+
+
+ private String[] maFinalValues;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleTypeReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleTypeReference.java
new file mode 100644
index 000000000000..5925b8fd0ead
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleTypeReference.java
@@ -0,0 +1,107 @@
+/**************************************************************
+*
+* 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.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class SimpleTypeReference
+ extends Node
+ implements INodeReference
+{
+ public SimpleTypeReference (
+ final Node aParent,
+ final QualifiedName aReferencedTypeName,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maReferencedTypeName = aReferencedTypeName;
+ }
+
+
+
+
+ public SimpleType GetReferencedSimpleType (final SchemaBase aSchemaBase)
+ {
+ final Node aType = aSchemaBase.GetTypeForName(maReferencedTypeName);
+ if (aType == null)
+ throw new RuntimeException("there is no type named '"+maReferencedTypeName+"' in the schema");
+ else if (aType.GetNodeType()!=NodeType.SimpleType && aType.GetNodeType()!=NodeType.BuiltIn)
+ throw new RuntimeException("name '"+maReferencedTypeName+"' references a "+aType.GetNodeType()+" not a simple type or builtin");
+ else
+ return (SimpleType)aType;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchemaBase)
+ {
+ return GetReferencedSimpleType(aSchemaBase);
+ }
+
+
+
+
+ public QualifiedName GetReferencedTypeName()
+ {
+ return maReferencedTypeName;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.SimpleTypeReference;
+ }
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "reference to simple type "+maReferencedTypeName;
+ }
+
+
+
+
+ private final QualifiedName maReferencedTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Union.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Union.java
new file mode 100644
index 000000000000..78c2171c65dd
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Union.java
@@ -0,0 +1,68 @@
+/**************************************************************
+*
+* 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.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** Representation of the 'union' XML schema element.
+ * Its set of valid values is the union of all of its children.
+ */
+public class Union
+ extends Node
+{
+ public Union (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Union;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "union";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/FormDefault.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/FormDefault.java
new file mode 100644
index 000000000000..ac03f94d53a2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/FormDefault.java
@@ -0,0 +1,31 @@
+/**************************************************************
+*
+* 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.parser;
+
+/** Enumeration of the form default values for attributes and elements in
+ * XML documents.
+ */
+public enum FormDefault
+{
+ qualified,
+ unqualified;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/SchemaParser.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/SchemaParser.java
new file mode 100644
index 000000000000..6e7bbb172691
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/SchemaParser.java
@@ -0,0 +1,1211 @@
+/**************************************************************
+*
+* 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.parser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+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.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.schema.Schema;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+
+/** Parser for single schema file.
+ * Imports and includes of other schema files are stored and can be retrieved
+ * by calling GetImportedSchemas().
+ *
+ * Typical usage:
+ * 1) Create SchemaParser for top-level schema file.
+ * 2) Call Parse().
+ * 3) Repeat the same recursively for all imported schemas (as returned by
+ * GetImportedSchemas()).
+ *
+ * All top level types (complex types, simple types, elements, etc.) are
+ * stored in the given Schema object.
+ */
+public class SchemaParser
+{
+ public SchemaParser (
+ final File aSchemaFile,
+ final Schema aSchema,
+ final SchemaBase aSchemaBase)
+ {
+ maSchema = aSchema;
+ maSchemaBase = aSchemaBase;
+ maReader = GetStreamReader(aSchemaFile);
+ msBasename = aSchemaFile.getName();
+ maDirectory = aSchemaFile.getParentFile();
+ maLocalNamespaceMap = new HashMap<>();
+ maImportedSchemas = new Vector<>();
+ maLastLocation = null;
+ }
+
+
+
+
+ /** Parse the schema file.
+ * @return
+ * Return false if there is any error.
+ * @throws XMLStreamException
+ */
+ public void Parse ()
+ throws XMLStreamException
+ {
+ if (maReader == null)
+ return;
+
+ while (maReader.hasNext())
+ {
+ final int nCode = maReader.next();
+ switch (nCode)
+ {
+ case XMLStreamReader.START_ELEMENT:
+ if (maReader.getLocalName().equals("schema"))
+ {
+ ProcessSchemaTag();
+ ParseSchema();
+
+ maLastLocation = maReader.getLocation();
+ }
+ else
+ {
+ throw CreateErrorException("expecting top level element to be 'schema'");
+ }
+ break;
+
+ case XMLStreamReader.END_DOCUMENT:
+ return;
+
+ default:
+ throw CreateErrorException("unexpected XML event %d", nCode);
+ }
+ }
+ }
+
+
+
+
+ public Iterable<File> GetImportedSchemaFilenames ()
+ {
+ return maImportedSchemas;
+ }
+
+
+
+
+ public int GetLineCount ()
+ {
+ if (maLastLocation != null)
+ return maLastLocation.getLineNumber();
+ else
+ return 0;
+ }
+
+
+
+
+ public int GetByteCount ()
+ {
+ if (maLastLocation != null)
+ return maLastLocation.getCharacterOffset();
+ else
+ return 0;
+ }
+
+
+
+
+ /** Process the namespace definitions in the outer 'schema' element.
+ */
+ private void ProcessSchemaTag ()
+ {
+ GetOptionalAttributeValue("id", null);
+ meAttributeFormDefault = FormDefault.valueOf(
+ GetOptionalAttributeValue("attributeFormDefault", "unqualified"));
+ meElementFormDefault = FormDefault.valueOf(
+ GetOptionalAttributeValue("elementFormDefault", "unqualified"));
+ GetOptionalAttributeValue("blockDefault", null);//=(#all|list of (extension|restriction|substitution))
+ GetOptionalAttributeValue("finalDefault", null);//=(#all|list of (extension|restriction|list|union))
+ msTargetNamespace = GetOptionalAttributeValue("targetNamespace", null);
+ GetOptionalAttributeValue("version", null);
+
+ for (int nIndex=0; nIndex<maReader.getNamespaceCount(); ++nIndex)
+ {
+ final String sPrefix = maReader.getNamespacePrefix(nIndex);
+ final String sURI = maReader.getNamespaceURI(nIndex);
+ maLocalNamespaceMap.put(sPrefix, sURI);
+ maSchemaBase.Namespaces.ProvideNamespace(sURI, sPrefix);
+ }
+
+ maLocalNamespaceMap.put(null, msTargetNamespace);
+ maSchemaBase.Namespaces.ProvideNamespace(msTargetNamespace, null);
+ }
+
+
+
+
+ private void ParseSchema ()
+ throws XMLStreamException
+ {
+ while (true)
+ {
+ switch (Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ ProcessTopLevelStartElement();
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return;
+
+ default:
+ throw CreateErrorException("unexpected event (expteced START_ELEMENT): %d", maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private void ProcessTopLevelStartElement ()
+ throws XMLStreamException
+ {
+ assert(GetAttributeValue("minOccurs") == null);
+ assert(GetAttributeValue("maxOccurs") == null);
+
+ switch (maReader.getLocalName())
+ {
+ case "attribute":
+ maSchemaBase.Attributes.Add(ParseAttribute());
+ break;
+
+ case "attributeGroup":
+ maSchemaBase.AttributeGroups.Add(ParseAttributeGroup());
+ break;
+
+ case "complexType":
+ maSchemaBase.ComplexTypes.Add(ParseComplexType());
+ break;
+
+ case "element":
+ final Element aElement = ParseElement(null);
+ if (maSchema != null)
+ maSchema.TopLevelElements.Add(aElement);
+ maSchemaBase.TopLevelElements.Add(aElement);
+ break;
+
+ case "group":
+ maSchemaBase.Groups.Add(ParseGroup(null));
+ break;
+
+ case "import":
+ ParseImport();
+ break;
+
+ case "include":
+ ParseInclude();
+ break;
+
+ case "simpleType":
+ maSchemaBase.SimpleTypes.Add(ParseSimpleType(null));
+ break;
+
+ default:
+ throw CreateErrorException("unexpected top level element %s", maReader.getLocalName());
+ }
+ }
+
+
+
+
+ private void ProcessStartElement (final Node aParent)
+ throws XMLStreamException
+ {
+ final String sMinimumOccurrence = GetOptionalAttributeValue("minOccurs", "1");
+ final String sMaximumOccurrence = GetOptionalAttributeValue("maxOccurs", "1");
+
+ final Node aLocalParent;
+ if ( ! (sMinimumOccurrence.equals("1") && sMaximumOccurrence.equals("1")))
+ {
+ // Occurrence does not only have default values (min=max=1).
+ // Have to create an intermediate node for the occurrence indicator.
+ final OccurrenceIndicator aIndicator = new OccurrenceIndicator(
+ aParent,
+ sMinimumOccurrence,
+ sMaximumOccurrence,
+ GetLocation());
+ aParent.AddChild(aIndicator);
+ aLocalParent = aIndicator;
+ }
+ else
+ aLocalParent = aParent;
+
+ switch (maReader.getLocalName())
+ {
+ case "all":
+ aLocalParent.AddChild(ParseAll(aLocalParent));
+ break;
+
+ case "any":
+ aLocalParent.AddChild(ParseAny(aLocalParent));
+ break;
+
+ case "attribute":
+ aLocalParent.AddAttribute(ParseAttributeOrReference());
+ break;
+
+ case "attributeGroup":
+ aLocalParent.AddAttribute(ParseAttributeGroupOrReference());
+ break;
+
+ case "choice":
+ aLocalParent.AddChild(ParseChoice(aLocalParent));
+ break;
+
+ case "complexContent":
+ aLocalParent.AddChild(ParseComplexContent(aLocalParent));
+ break;
+
+ case "element":
+ aLocalParent.AddChild(ParseElementOrReference(aLocalParent));
+ break;
+
+ case "extension":
+ aLocalParent.AddChild(ParseExtension(aLocalParent));
+ break;
+
+ case "group":
+ aLocalParent.AddChild(ParseGroupOrReference(aLocalParent));
+ break;
+
+ case "list":
+ aLocalParent.AddChild(ParseList(aLocalParent));
+ break;
+
+ case "sequence":
+ aLocalParent.AddChild(ParseSequence(aLocalParent));
+ break;
+
+ case "simpleContent":
+ aLocalParent.AddChild(ParseSimpleContent(aLocalParent));
+ break;
+
+ default:
+ throw CreateErrorException("unsupported content type %s", maReader.getLocalName());
+ }
+ }
+
+
+
+
+ private void IgnoreAnnotation ()
+ throws XMLStreamException
+ {
+ IgnoreContent();
+ }
+
+
+
+
+ private void IgnoreContent ()
+ throws XMLStreamException
+ {
+ while(true)
+ {
+ switch(maReader.next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ IgnoreContent();
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return;
+
+ case XMLStreamReader.COMMENT:
+ case XMLStreamReader.CHARACTERS:
+ break;
+
+ default:
+ throw CreateErrorException(
+ "unexpected XML event %d while ignoring content",
+ maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private All ParseAll (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs"));
+
+ final All aAll = new All(aParent, GetLocation());
+ ParseContent(aAll);
+ return aAll;
+ }
+
+
+
+
+ private Any ParseAny (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "namespace", "processContents"));
+
+ final Any aAny = new Any(
+ aParent,
+ GetLocation(),
+ GetOptionalAttributeValue("processContents", "strict"),
+ GetOptionalAttributeValue("namespace", "##any"));
+ ExpectEndElement("ParseAny");
+ return aAny;
+ }
+
+
+
+
+ private AttributeGroup ParseAttributeGroup ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("name"));
+
+ final AttributeGroup aGroup = new AttributeGroup(GetOptionalQualifiedName("name"), GetLocation());
+
+ while (true)
+ {
+ switch (Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ if ( ! maReader.getLocalName().equals("attribute"))
+ throw CreateErrorException(
+ "attributeGroup expects element 'attribute' but got %s",
+ maReader.getLocalName());
+ else
+ aGroup.AddAttribute(ParseAttributeOrReference());
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return aGroup;
+
+ default:
+ throw CreateErrorException(
+ "unexpected event when parsing attributeGroup: %d",
+ maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private INode ParseAttributeGroupOrReference ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("ref"));
+
+ final INode aGroup;
+ if (GetAttributeValue("schemaLocation") != null)
+ {
+ aGroup = ParseAttributeGroup();
+ }
+ else
+ {
+ aGroup = new AttributeGroupReference(
+ CreateQualifiedName(
+ GetAttributeValue("ref")),
+ GetLocation());
+ ExpectEndElement("attribute group or reference");
+ }
+ return aGroup;
+ }
+
+
+
+
+ private INode ParseAttributeOrReference ()
+ throws XMLStreamException
+ {
+ final INode aAttribute;
+ if (GetAttributeValue("name") != null)
+ {
+ aAttribute = ParseAttribute();
+ }
+ else
+ {
+ assert(HasOnlyAttributes("default", "fixed", "ref", "use"));
+
+ aAttribute = new AttributeReference(
+ GetQualifiedName("ref"),
+ GetOptionalAttributeValue("use", "optional"),
+ GetOptionalAttributeValue("default", null),
+ GetOptionalAttributeValue("fixed", null),
+ meAttributeFormDefault,
+ GetLocation());
+ ExpectEndElement("attribute reference");
+ }
+ return aAttribute;
+ }
+
+
+
+
+ private Attribute ParseAttribute ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("default", "fixed", "name", "type", "use"));
+
+ final Attribute aAttribute = new Attribute(
+ GetQualifiedName("name"),
+ GetQualifiedName("type"),
+ GetOptionalAttributeValue("use", "optional"),
+ GetOptionalAttributeValue("default", null),
+ GetOptionalAttributeValue("fixed", null),
+ meAttributeFormDefault,
+ GetLocation());
+ ExpectEndElement("attribute");
+
+ return aAttribute;
+ }
+
+
+
+ private Choice ParseChoice (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs"));
+
+ final Choice aChoice = new Choice(aParent, GetLocation());
+ ParseContent(aChoice);
+ return aChoice;
+ }
+
+
+
+
+ private ComplexContent ParseComplexContent (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs"));
+
+ final ComplexContent aNode = new ComplexContent(aParent, GetLocation());
+ ParseContent(aNode);
+ return aNode;
+ }
+
+
+
+
+ private ComplexType ParseComplexType ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("mixed", "name"));
+
+ final ComplexType aComplexType = new ComplexType(
+ null,
+ GetQualifiedName("name"),
+ GetLocation());
+
+ ParseContent(aComplexType);
+
+ return aComplexType;
+ }
+
+
+
+
+ private Element ParseElement (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "name", "type"));
+
+ final Element aElement = new Element(
+ aParent,
+ GetQualifiedName("name"),
+ GetQualifiedName("type"),
+ GetLocation());
+
+ ExpectEndElement("element");
+
+ return aElement;
+ }
+
+
+
+
+ private Element ParseElementOrReference (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "name", "ref", "type"));
+
+ final Element aElement;
+ final String sName = GetOptionalAttributeValue("name", null);
+ if (sName != null)
+ {
+ aElement = ParseElement(aParent);
+ }
+ else
+ {
+ final String sElementReference = GetOptionalAttributeValue("ref", null);
+ if (sElementReference != null)
+ {
+ ExpectEndElement("element reference");
+ aElement = new ElementReference(
+ aParent,
+ CreateQualifiedName(sElementReference),
+ GetLocation());
+ }
+ else
+ {
+ throw CreateErrorException("element has no name and no ref");
+ }
+ }
+ return aElement;
+ }
+
+
+
+
+ private Extension ParseExtension (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("base", "minOccurs", "maxOccurs"));
+
+ final Extension aNode = new Extension(
+ aParent,
+ CreateQualifiedName(GetAttributeValue("base")),
+ GetLocation());
+ ParseContent(aNode);
+ return aNode;
+ }
+
+
+
+
+ private Group ParseGroup (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("name"));
+
+ final Group aGroup = new Group(
+ aParent,
+ GetQualifiedName("name"),
+ GetLocation());
+ ParseContent(aGroup);
+ return aGroup;
+ }
+
+
+
+
+ private Node ParseGroupOrReference (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "name", "ref"));
+
+ final Node aGroup;
+ final String sName = GetOptionalAttributeValue("name", null);
+ if (sName != null)
+ {
+ aGroup = ParseGroup(aParent);
+ }
+ else
+ {
+ final String sGroupReference = GetOptionalAttributeValue("ref", null);
+ if (sGroupReference != null)
+ {
+ ExpectEndElement("group reference");
+ aGroup = new GroupReference(
+ aParent,
+ CreateQualifiedName(sGroupReference),
+ GetLocation());
+ }
+ else
+ {
+ throw CreateErrorException("group has no name and no ref");
+ }
+ }
+ return aGroup;
+ }
+
+
+
+
+ private Restriction ParseRestriction (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("base", "value"));
+
+ final String sBaseType = GetAttributeValue("base");
+ final Restriction aRestriction = new Restriction(
+ aParent,
+ CreateQualifiedName(sBaseType),
+ GetLocation());
+
+ while (true)
+ {
+ switch (Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ final String sValue = GetAttributeValue("value");
+ switch (maReader.getLocalName())
+ {
+ case "enumeration":
+ aRestriction.AddEnumeration(sValue);
+ break;
+
+ case "minInclusive":
+ aRestriction.SetMinInclusive(sValue);
+ break;
+
+ case "minExclusive":
+ aRestriction.SetMinExclusive(sValue);
+ break;
+
+ case "maxInclusive":
+ aRestriction.SetMaxInclusive(sValue);
+ break;
+
+ case "maxExclusive":
+ aRestriction.SetMaxExclusive(sValue);
+ break;
+
+ case "length":
+ aRestriction.SetLength(sValue);
+ break;
+
+ case "minLength":
+ aRestriction.SetMinLength(sValue);
+ break;
+
+ case "maxLength":
+ aRestriction.SetMaxLength(sValue);
+ break;
+
+ case "pattern":
+ aRestriction.SetPattern(sValue);
+ break;
+
+ default:
+ throw CreateErrorException("unsupported restriction type "+maReader.getLocalName());
+ }
+ ExpectEndElement("restriction");
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return aRestriction;
+
+ default:
+ throw CreateErrorException("unexpected XML event while parsing restrictions: %d", maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private List ParseList (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("itemType"));
+
+ final List aList = new List(
+ aParent,
+ GetQualifiedName("itemType"),
+ GetLocation());
+ ExpectEndElement("list");
+ return aList;
+ }
+
+
+
+
+ private Sequence ParseSequence (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "name"));
+
+ final Sequence aSequence = new Sequence(
+ aParent,
+ GetOptionalQualifiedName("name"),
+ GetLocation());
+ ParseContent(aSequence);
+ return aSequence;
+ }
+
+
+
+
+ private SimpleContent ParseSimpleContent (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs"));
+
+ final SimpleContent aSimpleContent = new SimpleContent(
+ aParent,
+ GetLocation());
+ ParseContent(aSimpleContent);
+ return aSimpleContent;
+ }
+
+
+
+
+ private SimpleType ParseSimpleType (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("final", "name"));
+
+ final SimpleType aType = new SimpleType(
+ aParent,
+ GetQualifiedName("name"),
+ GetLocation());
+ final String sFinalValue = GetOptionalAttributeValue("final", null);
+ if (sFinalValue != null)
+ aType.SetFinal(sFinalValue.split("\\s+"));
+
+ while (true)
+ {
+ switch (Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ switch(maReader.getLocalName())
+ {
+ case "list":
+ aType.AddChild(ParseList(aType));
+ break;
+
+ case "restriction":
+ aType.AddChild(ParseRestriction(aType));
+ break;
+
+ case "union":
+ aType.AddChild(ParseUnion(aType));
+ break;
+
+ default:
+ throw CreateErrorException("unsupported simple type part %s", maReader.getLocalName());
+ }
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return aType;
+
+ default:
+ throw CreateErrorException("unexpected XML event in ParseSimpleType: %s", maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private Union ParseUnion (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("memberTypes"));
+
+ final Union aUnion = new Union(
+ aParent,
+ GetLocation());
+ final String[] aMemberTypes = GetAttributeValue("memberTypes").split("\\s+");
+ for (int nIndex=0; nIndex<aMemberTypes.length; ++nIndex)
+ aUnion.AddChild(
+ new SimpleTypeReference(
+ aUnion,
+ CreateQualifiedName(aMemberTypes[nIndex]),
+ GetLocation()));
+
+ ParseContent(aUnion);
+
+ return aUnion;
+ }
+
+
+ private void ParseContent (final Node aParent)
+ throws XMLStreamException
+ {
+ while(true)
+ {
+ switch(Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ ProcessStartElement(aParent);
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return;
+
+ default:
+ throw CreateErrorException(
+ "unexpected XML event %d while parsing content of %s",
+ maReader.getEventType(),
+ aParent.toString());
+ }
+ }
+ }
+
+
+
+
+ private void ParseImport ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("id", "namespace", "schemaLocation"));
+
+ final String sFilename = GetOptionalAttributeValue("schemaLocation", null);
+ if (sFilename == null)
+ {
+ final String sNamespaceName = GetAttributeValue("namespace");
+ if (sNamespaceName.equals(XmlNamespace.URI))
+ {
+ XmlNamespace.Apply(maSchemaBase);
+ maLocalNamespaceMap.put(XmlNamespace.Prefix, XmlNamespace.URI);
+ }
+ else
+ throw CreateErrorException("invalid import");
+ }
+ else
+ {
+ maImportedSchemas.add(new File(maDirectory, sFilename));
+ }
+
+ ExpectEndElement("import");
+ }
+
+
+
+
+ private void ParseInclude ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("id", "schemaLocation"));
+
+ final String sFilename = GetOptionalAttributeValue("schemaLocation", null);
+ if (sFilename == null)
+ {
+ throw CreateErrorException("invalid include");
+ }
+ else
+ {
+ maImportedSchemas.add(new File(maDirectory, sFilename));
+ }
+
+ ExpectEndElement("include");
+ }
+
+
+
+
+ private void ExpectEndElement (final String sCaller)
+ throws XMLStreamException
+ {
+ final int nNextEvent = Next();
+ if (nNextEvent != XMLStreamReader.END_ELEMENT)
+ throw CreateErrorException("expected END_ELEMENT of %s but got %s",
+ sCaller,
+ nNextEvent);
+ }
+
+
+
+
+ /** Return the next relevant token from the XML stream.
+ * Ignores comments.
+ * @return
+ * Returns the event code of the next relevant XML event or END_DOCUMENT when the end of the file has been reached.
+ */
+ private int Next ()
+ throws XMLStreamException
+ {
+ while (maReader.hasNext())
+ {
+ switch (maReader.next())
+ {
+ case XMLStreamReader.COMMENT:
+ // Ignore comments.
+ break;
+
+ case XMLStreamReader.CHARACTERS:
+ // Ignore whitespace.
+ if (maReader.getText().matches("^\\s+$"))
+ break;
+ else
+ {
+ // Character events are not expected in schema files
+ // and therefore not supported.
+ // Alternatively, they could easily be ignored.
+ throw CreateErrorException("unexpected CHARACTERS event with text [%s]", maReader.getText());
+ }
+
+ case XMLStreamReader.START_ELEMENT:
+ switch (maReader.getLocalName())
+ {
+ case "annotation":
+ IgnoreAnnotation();
+ break;
+ case "unique":
+ // Not supported.
+ IgnoreContent();
+ break;
+ default:
+ return XMLStreamReader.START_ELEMENT;
+ }
+ break;
+
+ default:
+ return maReader.getEventType();
+ }
+ }
+ return XMLStreamReader.END_DOCUMENT;
+ }
+
+
+
+
+ private String GetAttributeValue (final String sAttributeLocalName)
+ {
+ return maReader.getAttributeValue(null, sAttributeLocalName);
+ }
+
+
+
+
+ private String GetOptionalAttributeValue (
+ final String sAttributeLocalName,
+ final String sDefaultValue)
+ {
+ final String sValue = maReader.getAttributeValue(null, sAttributeLocalName);
+ if (sValue == null)
+ return sDefaultValue;
+ else
+ return sValue;
+ }
+
+
+
+
+ /** Read the specified attribute and return its value as QualifiedName object.
+ */
+ private QualifiedName GetQualifiedName (final String sAttributeLocalName)
+ {
+ final String sName = maReader.getAttributeValue(null, sAttributeLocalName);
+ if (sName == null)
+ throw CreateErrorException(
+ "did not find a qualified name as value of attribute '%s' at %s:%s",
+ sAttributeLocalName,
+ msBasename,
+ maReader.getLocation());
+ else
+ return CreateQualifiedName(sName);
+ }
+
+
+
+
+ private QualifiedName GetOptionalQualifiedName (final String sAttributeLocalName)
+ {
+ final String sName = maReader.getAttributeValue(null, sAttributeLocalName);
+ if (sName == null)
+ return null;
+ else
+ return CreateQualifiedName(sName);
+ }
+
+
+
+
+ /** Create a QualifiedName object from the given string.
+ * @param sName
+ * May or may not contain a namespace prefix (separated from the name
+ * by a colon).
+ */
+ private QualifiedName CreateQualifiedName (final String sName)
+ {
+ final String[] aParts = sName.split(":");
+ final String sNamespaceURL;
+ final String sLocalPart;
+ switch (aParts.length)
+ {
+ case 1:
+ // sName only consists of a local part.
+ // Use the target namespace as namespace.
+ sNamespaceURL = msTargetNamespace;
+ sLocalPart = aParts[0];
+ break;
+
+ case 2:
+ // sName is of the form prefix:local.
+ sNamespaceURL = maLocalNamespaceMap.get(aParts[0]);
+ sLocalPart = aParts[1];
+ break;
+
+ default:
+ throw new RuntimeException(
+ "the string '"+sName+"' can not be transformed into a qualified name");
+ }
+ if (sNamespaceURL == null)
+ throw CreateErrorException("can not determine namespace for '%s'", sName);
+ // Transform the local namespace prefix into a global namespace prefix
+ // (different schema files can use different prefixes for the same
+ // namespace URI).
+ final String sGlobalNamespacePrefix = maSchemaBase.Namespaces.GetNamespacePrefix(sNamespaceURL);
+ return new QualifiedName(
+ sNamespaceURL,
+ sGlobalNamespacePrefix,
+ sLocalPart);
+ }
+
+
+
+
+ /** Create an XMLStreamReader for the given file.
+ * Returns null when there is an error.
+ */
+ private static XMLStreamReader GetStreamReader (final File aSchemaFile)
+ {
+ final XMLInputFactory aFactory = (XMLInputFactory)XMLInputFactory.newInstance();
+ aFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+ aFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+ aFactory.setProperty(XMLInputFactory.IS_COALESCING, false);
+
+ try
+ {
+ return aFactory.createXMLStreamReader(
+ aSchemaFile.getName(),
+ new FileInputStream(aSchemaFile));
+ }
+ catch (Exception aException)
+ {
+ aException.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+
+ private RuntimeException CreateErrorException (
+ final String sFormat,
+ final Object ... aArgumentList)
+ {
+ return new RuntimeException(String.format(sFormat, aArgumentList)
+ + String.format(" in %s at L%dC%dP%d",
+ msBasename,
+ maReader.getLocation().getLineNumber(),
+ maReader.getLocation().getColumnNumber(),
+ maReader.getLocation().getCharacterOffset()));
+ }
+
+
+
+
+ /** This predicate is only used for debugging to assert
+ * that no unsupported attributes are present.
+ * If there where then the parser has to be extended.
+ */
+ private boolean HasOnlyAttributes (final String ... aAttributeNameList)
+ {
+ for (int nIndex=0,nCount=maReader.getAttributeCount(); nIndex<nCount; ++nIndex)
+ {
+ final String sAttributeName = maReader.getAttributeLocalName(nIndex);
+ boolean bFound = false;
+ for (final String sName : aAttributeNameList)
+ if (sAttributeName.equals(sName))
+ {
+ bFound = true;
+ break;
+ }
+ if ( ! bFound)
+ {
+ // Attribute name was not found in the given list.
+ System.err.printf("attribute '%s' is not handled\n", sAttributeName);
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+
+
+ private Location GetLocation ()
+ {
+ final javax.xml.stream.Location aLocation = maReader.getLocation();
+ return new Location(
+ msBasename,
+ aLocation.getLineNumber(),
+ aLocation.getColumnNumber(),
+ aLocation.getCharacterOffset());
+ }
+
+
+
+
+ private final Schema maSchema;
+ private final SchemaBase maSchemaBase;
+ private final XMLStreamReader maReader;
+ private final String msBasename;
+ private final File maDirectory;
+ private String msTargetNamespace;
+ /// Map of namespace prefix to URI, local to the currently read schema file.
+ private final Map<String,String> maLocalNamespaceMap;
+ /// The names of other schema files referenced by import elements.
+ private final Vector<File> maImportedSchemas;
+ /// Some values for tracking the number of read bytes and lines.
+ private javax.xml.stream.Location maLastLocation;
+ private FormDefault meAttributeFormDefault;
+ private FormDefault meElementFormDefault;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XmlNamespace.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XmlNamespace.java
new file mode 100644
index 000000000000..078c9e13de10
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XmlNamespace.java
@@ -0,0 +1,69 @@
+/**************************************************************
+*
+* 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.parser;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+/** The http://www.w3.org/XML/1998/namespace namespace is
+ * implicitly included in all schema files.
+ *
+ * This class makes the necessary additions to namespace map and Schema object.
+ */
+public class XmlNamespace
+{
+ public static final String URI = "http://www.w3.org/XML/1998/namespace";
+ public static final String Prefix = "xml";
+
+ public static void Apply (final SchemaBase aSchemaBase)
+ {
+ aSchemaBase.Namespaces.ProvideNamespace(URI, Prefix);
+
+ final QualifiedName aStSpaceSimpleTypeName = new QualifiedName(URI, Prefix, "ST__space");
+ aSchemaBase.Attributes.Add(
+ new Attribute(
+ new QualifiedName(URI, Prefix, "space"),
+ aStSpaceSimpleTypeName,
+ "optional",
+ null,
+ null,
+ FormDefault.unqualified,
+ null));
+
+ final SimpleType aType = new SimpleType(
+ null,
+ aStSpaceSimpleTypeName,
+ new Location());
+ final Restriction aRestriction = new Restriction(
+ aType,
+ new QualifiedName(XsdNamespace.URI, XsdNamespace.Prefix, "token"),
+ null);
+ aRestriction.AddEnumeration("default");
+ aRestriction.AddEnumeration("preserve");
+ aType.AddChild(aRestriction);
+ aSchemaBase.SimpleTypes.Add(aType);
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XsdNamespace.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XsdNamespace.java
new file mode 100644
index 000000000000..901aca5efdc9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XsdNamespace.java
@@ -0,0 +1,29 @@
+/**************************************************************
+*
+* 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.parser;
+
+
+public class XsdNamespace
+{
+ public static final String URI = "http://www.w3.org/2001/XMLSchema";
+ public static final String Prefix = "xsd";
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/BlobNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/BlobNode.java
new file mode 100644
index 000000000000..ab0a4fcf44cc
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/BlobNode.java
@@ -0,0 +1,131 @@
+/**************************************************************
+*
+* 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.simple;
+
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltInType;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class BlobNode
+ implements ISimpleTypeNode
+{
+ public BlobNode (final BuiltInType eType)
+ {
+ meType = eType;
+ mbIsList = false;
+ mnLengthRestriction = null;
+ }
+
+
+
+
+ public BuiltInType GetBlobType ()
+ {
+ return meType;
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aRestriction,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ if (aRestriction.GetFeatureBits() == 0)
+ return;
+
+ if (aRestriction.GetFeatureBits() != Restriction.LengthBit)
+ throw new RuntimeException("unsupported restriction on blob: "+aRestriction);
+
+ mnLengthRestriction = aRestriction.GetLength();
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.printf("blob of type %s\n", meType);
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ public enum RestrictionType
+ {
+ Length,
+ None;
+ }
+ public RestrictionType GetRestrictionType ()
+ {
+ if (mnLengthRestriction != null)
+ return RestrictionType.Length;
+ else
+ return RestrictionType.None;
+ }
+
+
+
+
+ public int GetLengthRestriction ()
+ {
+ return mnLengthRestriction;
+ }
+
+
+
+
+ private final BuiltInType meType;
+ private boolean mbIsList;
+ private Integer mnLengthRestriction;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/DateTimeNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/DateTimeNode.java
new file mode 100644
index 000000000000..9f32145bf55c
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/DateTimeNode.java
@@ -0,0 +1,92 @@
+/**************************************************************
+*
+* 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.simple;
+
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltInType;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class DateTimeNode
+ implements ISimpleTypeNode
+{
+
+ public DateTimeNode (final BuiltInType eType)
+ {
+ mbIsList = false;
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aRestriction,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ if (aRestriction.GetFeatureBits() == 0)
+ return;
+ System.out.println(aRestriction);
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.printf("date or time\n");
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ private boolean mbIsList;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/EnumerationNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/EnumerationNode.java
new file mode 100644
index 000000000000..f4844aeaab59
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/EnumerationNode.java
@@ -0,0 +1,27 @@
+/**************************************************************
+*
+* 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.simple;
+
+public class EnumerationNode
+{
+
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNode.java
new file mode 100644
index 000000000000..6698b856ccc1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNode.java
@@ -0,0 +1,48 @@
+/**************************************************************
+*
+* 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.simple;
+
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+/** Represent a single node in the node tree of a simple type.
+ */
+public interface ISimpleTypeNode
+{
+ void ApplyRestriction (
+ final Restriction aNode,
+ final Map<String,Integer> aValueToIdMap);
+ void Print (final Log aLog);
+
+ /** List elements are not represented by their own node (type).
+ * There is only this flag that makes this node a list of the item type
+ * which is represented by the node.
+ */
+ boolean IsList ();
+
+ /** Set the IsList flag.
+ */
+ void SetIsList ();
+ void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor);
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNodeVisitor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNodeVisitor.java
new file mode 100644
index 000000000000..be7ea27b0b5d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNodeVisitor.java
@@ -0,0 +1,31 @@
+/**************************************************************
+*
+* 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.simple;
+
+public interface ISimpleTypeNodeVisitor
+{
+ void Visit (final BlobNode aType);
+ void Visit (final DateTimeNode aType);
+ void Visit (final NumberNode<?> aType);
+ void Visit (final StringNode aType);
+ void Visit (final UnionNode aType);
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/NumberNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/NumberNode.java
new file mode 100644
index 000000000000..6cbb320c6980
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/NumberNode.java
@@ -0,0 +1,310 @@
+/**************************************************************
+*
+* 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.simple;
+
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltInType;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class NumberNode<T extends Comparable<T>>
+ implements ISimpleTypeNode
+{
+ NumberNode (final BuiltInType eType)
+ {
+ meType = eType;
+ mbIsList = false;
+ }
+
+
+
+
+ public BuiltInType GetNumberType ()
+ {
+ return meType;
+ }
+
+
+
+
+ T ParseString (final String sValue)
+ {
+ switch(meType)
+ {
+ case Float:
+ return (T)(Float)Float.parseFloat(sValue);
+
+ case Double:
+ return (T)(Double)Double.parseDouble(sValue);
+
+ case Byte:
+ return (T)(Byte)Byte.parseByte(sValue);
+
+ case Int:
+ case UnsignedShort:
+ return (T)(Integer)Integer.parseInt(sValue);
+
+ case Short:
+ case UnsignedByte:
+ return (T)(Short)Short.parseShort(sValue);
+
+ case Long:
+ case UnsignedInt:
+ case Integer:
+ return (T)(Long)Long.parseLong(sValue);
+
+ default:
+ throw new RuntimeException("unsupported type "+meType);
+ }
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aNode,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ if (aNode.HasFeature(Restriction.MinExclusiveBit))
+ ApplyMinimum(ParseString(aNode.GetMinExclusive()), false);
+ if (aNode.HasFeature(Restriction.MinInclusiveBit))
+ ApplyMinimum(ParseString(aNode.GetMinInclusive()), true);
+
+ if (aNode.HasFeature(Restriction.MaxExclusiveBit))
+ ApplyMaximum(ParseString(aNode.GetMaxExclusive()), false);
+ if (aNode.HasFeature(Restriction.MaxInclusiveBit))
+ ApplyMaximum(ParseString(aNode.GetMaxInclusive()), true);
+
+ if (aNode.HasFeature(Restriction.EnumerationBit))
+ {
+ final Vector<T> aValues = new Vector<>();
+ for (final String sEnumerationValue : aNode.GetEnumeration())
+ aValues.add(ParseString(sEnumerationValue));
+ ApplyEnumeration(aValues);
+ }
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.printf("%s\n", toString());
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ final StringBuffer sMessage = new StringBuffer();
+ sMessage.append(meType);
+ if (maEnumeration != null)
+ {
+ sMessage.append(", restricted to values");
+ for (final T nValue : maEnumeration)
+ {
+ sMessage.append(' ');
+ sMessage.append(nValue);
+ }
+ }
+ else if (maMinimumValue!=null || maMaximumValue!=null)
+ {
+ sMessage.append(" restricted to ");
+
+ if (maMinimumValue != null)
+ {
+ sMessage.append(maMinimumValue);
+ if (mbIsMinimumInclusive)
+ sMessage.append(" <= ");
+ else
+ sMessage.append(" < ");
+ }
+ sMessage.append("value");
+ if (maMaximumValue != null)
+ {
+ if (mbIsMaximumInclusive)
+ sMessage.append(" <= ");
+ else
+ sMessage.append(" < ");
+ sMessage.append(maMaximumValue);
+ }
+ }
+ else
+ sMessage.append(", not restricted");
+
+ return sMessage.toString();
+ }
+
+
+
+
+ private void ApplyMinimum (
+ final T nValue,
+ final boolean bIsInclusive)
+ {
+ if (maEnumeration != null)
+ throw new RuntimeException("minimum can not be applied to an enumeration");
+ else if (maMinimumValue != null)
+ {
+ final int nComparison = maMinimumValue.compareTo(nValue);
+ if (nComparison > 0)
+ throw new RuntimeException("second restriction tries to enlarge value space");
+ else if (nComparison == 0)
+ if (mbIsMinimumInclusive && ! bIsInclusive)
+ throw new RuntimeException("second restriction tries to enlarge value space");
+ }
+ maMinimumValue = nValue;
+ mbIsMinimumInclusive = bIsInclusive;
+ }
+
+
+
+
+
+ private void ApplyMaximum (
+ final T nValue,
+ final boolean bIsInclusive)
+ {
+ if (maEnumeration != null)
+ throw new RuntimeException("maximum can not be applied to an enumeration");
+ else if (maMaximumValue != null)
+ {
+ final int nComparison = maMaximumValue.compareTo(nValue);
+ if (nComparison < 0)
+ throw new RuntimeException("second restriction tries to enlarge value space");
+ else if (nComparison == 0)
+ if ( ! mbIsMaximumInclusive && bIsInclusive)
+ throw new RuntimeException("second restriction tries to enlarge value space");
+ }
+ maMaximumValue = nValue;
+ mbIsMaximumInclusive = bIsInclusive;
+ }
+
+
+
+
+ private void ApplyEnumeration (final Vector<T> aValues)
+ {
+ if (maEnumeration!=null || maMaximumValue!=null || maMinimumValue!=null)
+ throw new RuntimeException("can not apply enumeration to existing restriction");
+ maEnumeration = aValues;
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+ public enum RestrictionType
+ {
+ Size,
+ Enumeration,
+ None
+ }
+ public RestrictionType GetRestrictionType ()
+ {
+ if (maEnumeration != null)
+ return RestrictionType.Enumeration;
+ else if (maMinimumValue!=null || maMaximumValue!=null)
+ return RestrictionType.Size;
+ else
+ return RestrictionType.None;
+ }
+
+
+
+ public Iterable<T> GetEnumerationRestriction ()
+ {
+ return maEnumeration;
+ }
+
+
+
+
+ public T GetMinimum ()
+ {
+ return maMinimumValue;
+ }
+
+
+
+
+ public T GetMaximum ()
+ {
+ return maMaximumValue;
+ }
+
+
+
+ public boolean IsMinimumInclusive ()
+ {
+ return mbIsMinimumInclusive;
+ }
+
+
+
+
+ public boolean IsMaximumInclusive ()
+ {
+ return mbIsMaximumInclusive;
+ }
+
+
+
+
+ private final BuiltInType meType;
+ private T maMinimumValue;
+ private boolean mbIsMinimumInclusive;
+ private T maMaximumValue;
+ private boolean mbIsMaximumInclusive;
+ private Vector<T> maEnumeration;
+ private boolean mbIsList;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeContainer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeContainer.java
new file mode 100644
index 000000000000..c77294c557a9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeContainer.java
@@ -0,0 +1,102 @@
+/**************************************************************
+*
+* 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.simple;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+public class SimpleTypeContainer
+{
+ public static SimpleTypeContainer Create (
+ final SchemaBase aSchemaBase,
+ final File aLogFile)
+ {
+ final SimpleTypeContainer aContainer = new SimpleTypeContainer(aLogFile);
+ for (final SimpleType aType : aSchemaBase.SimpleTypes.GetSorted())
+ {
+ aContainer.ProcessSimpleType(aType, aSchemaBase);
+ }
+ return aContainer;
+ }
+
+
+
+
+ public int GetSimpleTypeCount ()
+ {
+ return maSimpleTypes.size();
+ }
+
+
+
+
+ public Iterable<Entry<String,SimpleTypeDescriptor>> GetSimpleTypes ()
+ {
+ return maSimpleTypes.entrySet();
+ }
+
+
+
+
+ public Iterable<Entry<String,SimpleTypeDescriptor>> GetSimpleTypesSorted ()
+ {
+ final Map<String,SimpleTypeDescriptor> aSortedSimpleTypes = new TreeMap<>();
+ aSortedSimpleTypes.putAll(maSimpleTypes);
+ return aSortedSimpleTypes.entrySet();
+ }
+
+
+
+
+ private SimpleTypeContainer (final File aLogFile)
+ {
+ maSimpleTypes = new TreeMap<>();
+ maLog = new Log(aLogFile);
+ }
+
+
+
+
+ private void ProcessSimpleType (
+ final SimpleType aType,
+ final SchemaBase aSchemaBase)
+ {
+ maSimpleTypes.put(
+ aType.GetName().GetStateName(),
+ SimpleTypeDescriptorFactory.CreateSimpleTypeDescriptor(
+ aType,
+ aSchemaBase,
+ maLog));
+ }
+
+
+
+
+ private final Map<String,SimpleTypeDescriptor> maSimpleTypes;
+ private final Log maLog;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptor.java
new file mode 100644
index 000000000000..0c415e11a3a7
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptor.java
@@ -0,0 +1,86 @@
+/**************************************************************
+*
+* 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.simple;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+public class SimpleTypeDescriptor
+{
+ public SimpleTypeDescriptor (
+ final QualifiedName aName)
+ {
+ maName = aName;
+ maSubTypes = null;
+ }
+
+
+
+
+ public QualifiedName GetName()
+ {
+ return maName;
+ }
+
+
+
+
+ public void SetSubTypes (final ISimpleTypeNode[] aSubTypes)
+ {
+ maSubTypes = aSubTypes;
+ }
+
+
+
+
+ public ISimpleTypeNode[] GetSubType ()
+ {
+ return maSubTypes;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "simple type "+maName;
+ }
+
+
+
+
+ public void Print (final Log aLog)
+ {
+ aLog.printf("%s\n", toString());
+ aLog.StartBlock();
+ for (final ISimpleTypeNode aSubType : maSubTypes)
+ aSubType.Print(aLog);
+ aLog.EndBlock();
+ }
+
+
+
+
+ private final QualifiedName maName;
+ private ISimpleTypeNode[] maSubTypes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptorFactory.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptorFactory.java
new file mode 100644
index 000000000000..55c1cf24c145
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptorFactory.java
@@ -0,0 +1,307 @@
+/**************************************************************
+*
+* 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.simple;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+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.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+public class SimpleTypeDescriptorFactory
+ extends NodeVisitorAdapter
+{
+ class TypeCounter
+ extends NodeVisitorAdapter
+ {
+ public final Map<NodeType,Integer> Counters;
+ TypeCounter ()
+ {
+ Counters = new HashMap<>();
+ for (final NodeType eType : NodeType.values())
+ Counters.put(eType, 0);
+ }
+ @Override
+ public void Default (final INode aNode)
+ {
+ Counters.put(aNode.GetNodeType(), Counters.get(aNode.GetNodeType())+1);
+ }
+ }
+
+
+
+
+ public static SimpleTypeDescriptor CreateSimpleTypeDescriptor(
+ final SimpleType aSimpleType,
+ final SchemaBase aSchemaBase,
+ final Log aLog)
+ {
+ final SimpleTypeDescriptorFactory aFactory = new SimpleTypeDescriptorFactory(
+ aSchemaBase,
+ aLog);
+
+ aLog.AddComment("Simple type %s, defined at %s",
+ aSimpleType.GetName(),
+ aSimpleType.GetLocation().toString());
+
+ final ISimpleTypeNode aSubType = aFactory.ProcessSimpleType(aSimpleType);
+ final SimpleTypeDescriptor aDescriptor = new SimpleTypeDescriptor(aSimpleType.GetName());
+ aSubType.AcceptVisitor(new SimpleTypeNodeVisitorAdapter ()
+ {
+ @Override public void Visit (final UnionNode aType)
+ {
+ aDescriptor.SetSubTypes(aType.GetChildren());
+ }
+
+ @Override public void Default (final ISimpleTypeNode aType)
+ {
+ aDescriptor.SetSubTypes(new ISimpleTypeNode[]{aSubType});
+ }
+ });
+
+ aDescriptor.Print(aLog);
+ aLog.printf("\n");
+
+ return aDescriptor;
+ }
+
+
+
+
+ private SimpleTypeDescriptorFactory (
+ final SchemaBase aSchemaBase,
+ final Log aLog)
+ {
+ maSchemaBase = aSchemaBase;
+ maLog = aLog;
+ maResult = null;
+ }
+
+
+
+
+ ISimpleTypeNode ProcessSimpleType (final SimpleType aSimpleType)
+ {
+ return ApplyVisitor(aSimpleType);
+ }
+
+
+
+
+ @Override
+ public void Visit (final BuiltIn aNode)
+ {
+ assert(aNode.GetChildCount() == 0);
+ assert(maResult == null);
+
+ maLog.AddComment("builtin %s", aNode.toString());
+
+ switch(aNode.GetBuiltInType())
+ {
+ case Double:
+ maResult = new NumberNode<Double>(aNode.GetBuiltInType());
+ break;
+ case Float:
+ maResult = new NumberNode<Float>(aNode.GetBuiltInType());
+ break;
+
+ case Boolean:
+ maResult = new NumberNode<Boolean>(aNode.GetBuiltInType());
+ case Integer:
+ maResult = new NumberNode<Long>(aNode.GetBuiltInType());
+ break;
+ case Byte:
+ maResult = new NumberNode<Byte>(aNode.GetBuiltInType());
+ case Int:
+ maResult = new NumberNode<Integer>(aNode.GetBuiltInType());
+ case Long:
+ maResult = new NumberNode<Long>(aNode.GetBuiltInType());
+ case Short:
+ maResult = new NumberNode<Short>(aNode.GetBuiltInType());
+ case UnsignedByte:
+ maResult = new NumberNode<Integer>(aNode.GetBuiltInType());
+ case UnsignedInt:
+ maResult = new NumberNode<Long>(aNode.GetBuiltInType());
+ case UnsignedLong:
+ maResult = new NumberNode<Long>(aNode.GetBuiltInType());
+ case UnsignedShort:
+ maResult = new NumberNode<Integer>(aNode.GetBuiltInType());
+ break;
+
+ case AnyURI:
+ case ID:
+ case NcName:
+ case String:
+ case Token:
+ maResult = new StringNode(aNode.GetBuiltInType());
+ break;
+
+ case Base64Binary:
+ case HexBinary:
+ maResult = new BlobNode(aNode.GetBuiltInType());
+ break;
+
+ case DateTime:
+ maResult = new DateTimeNode(aNode.GetBuiltInType());
+ break;
+
+ default:
+ throw new RuntimeException(aNode.toString()+" is not supported");
+ }
+ }
+
+
+
+
+ @Override
+ public void Visit (final List aNode)
+ {
+ maLog.AddComment("list of type %s", aNode.GetItemType().toString());
+ maLog.StartBlock();
+ final ISimpleTypeNode aItemType = ApplyVisitor(maSchemaBase.GetSimpleTypeForName(aNode.GetItemType()));
+ maLog.EndBlock();
+
+ aItemType.SetIsList();
+ maResult = aItemType;
+ }
+
+
+
+
+ @Override
+ public void Visit (final Restriction aNode)
+ {
+ assert(aNode.GetChildCount() == 0);
+
+ maLog.AddComment("%s", aNode.toString());
+
+ final INode aBaseType = maSchemaBase.GetSimpleTypeForName(aNode.GetBaseType());
+ if (aBaseType == null)
+ throw new RuntimeException("got no type for name "+aNode.GetBaseType());
+ maLog.StartBlock();
+ maResult = ApplyVisitor(aBaseType);
+ maLog.EndBlock();
+ maResult.ApplyRestriction(
+ aNode,
+ maSchemaBase.AttributeValueToIdMap);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleType aNode)
+ {
+ maLog.AddComment(aNode.toString());
+
+ assert(aNode.GetChildCount() <= 1);
+ switch(aNode.GetChildCount())
+ {
+ case 0:
+ maResult = null;
+ break;
+ case 1:
+ maLog.StartBlock();
+ maResult = ApplyVisitor(aNode.GetOnlyChild());
+ maLog.EndBlock();
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleTypeReference aNode)
+ {
+ maLog.AddComment("reference to %s", aNode.GetReferencedTypeName());
+
+ maLog.StartBlock();
+ maResult = ApplyVisitor(aNode.GetReferencedNode(maSchemaBase));
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final Union aNode)
+ {
+ maLog.AddComment("union");
+
+ final UnionNode aUnion = new UnionNode();
+
+ // Make sure that all children have compatible types and value sets.
+ maLog.StartBlock();
+
+ for (final INode aChild : aNode.GetChildren())
+ {
+ aUnion.AddNode(ApplyVisitor(aChild));
+ }
+
+ maLog.EndBlock();
+
+ maResult = aUnion;
+ }
+
+
+
+
+ @Override
+ public void Default (final INode aNode)
+ {
+ switch(aNode.GetNodeType())
+ {
+ default:
+ throw new RuntimeException(aNode.GetNodeType() +" is not yet supported");
+ }
+ }
+
+
+
+
+ ISimpleTypeNode ApplyVisitor (final INode aNode)
+ {
+ aNode.AcceptVisitor(this);
+ final ISimpleTypeNode aResult = maResult;
+ maResult = null;
+ return aResult;
+ }
+
+
+
+
+ private final SchemaBase maSchemaBase;
+ private final Log maLog;
+ private ISimpleTypeNode maResult;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeNodeVisitorAdapter.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeNodeVisitorAdapter.java
new file mode 100644
index 000000000000..9e30d653bb9a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeNodeVisitorAdapter.java
@@ -0,0 +1,60 @@
+/**************************************************************
+*
+* 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.simple;
+
+public class SimpleTypeNodeVisitorAdapter
+ implements ISimpleTypeNodeVisitor
+{
+ @Override
+ public void Visit(BlobNode aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit(DateTimeNode aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit(NumberNode<?> aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit(StringNode aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit(UnionNode aType)
+ {
+ Default(aType);
+ }
+
+ public void Default (final ISimpleTypeNode aType)
+ {
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/StringNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/StringNode.java
new file mode 100644
index 000000000000..b88da5c7e40a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/StringNode.java
@@ -0,0 +1,269 @@
+/**************************************************************
+*
+* 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.simple;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltInType;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class StringNode
+ implements ISimpleTypeNode
+{
+ public StringNode (
+ final BuiltInType eType)
+ {
+ meType = eType;
+ mbIsList = false;
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aRestriction,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ assert( ! aRestriction.HasFeature(
+ Restriction.MinExclusiveBit
+ | Restriction.MinInclusiveBit
+ | Restriction.MaxExclusiveBit
+ | Restriction.MaxInclusiveBit));
+
+ if (aRestriction.HasFeature(Restriction.EnumerationBit))
+ {
+ if (aRestriction.HasFeature(Restriction.LengthBit|Restriction.MinLengthBit|Restriction.MaxLengthBit))
+ for (final String sValue : aRestriction.GetEnumeration())
+ assert(CheckLengthRestriction(sValue, aRestriction));
+ maEnumerationValues = new TreeSet<>();
+ maEnumerationValueIds = new HashSet<>();
+ for (final String sValue : aRestriction.GetEnumeration())
+ {
+ if ( ! aValueToIdMap.containsKey(sValue))
+ aValueToIdMap.put(sValue, aValueToIdMap.size());
+ maEnumerationValues.add(sValue);
+ maEnumerationValueIds.add(aValueToIdMap.get(sValue));
+ }
+ }
+ else if (aRestriction.HasFeature(Restriction.PatternBit))
+ {
+ msPattern = aRestriction.GetPattern();
+ // Make the regular expression understandable by Java (by replacing
+ // character class names like IsBasicLatin to InBasicLatin).
+ try
+ {
+ maPattern = Pattern.compile(msPattern.replace("\\p{Is", "\\p{In"), Pattern.UNICODE_CHARACTER_CLASS);
+ }
+ catch (PatternSyntaxException aException)
+ {
+ aException.printStackTrace();
+ }
+ }
+ else if (aRestriction.HasFeature(Restriction.LengthBit|Restriction.MinLengthBit|Restriction.MaxLengthBit))
+ {
+ if (aRestriction.HasFeature(Restriction.LengthBit))
+ mnMinimumLength = mnMaximumLength = aRestriction.GetLength();
+ if (aRestriction.HasFeature(Restriction.MinLengthBit))
+ mnMinimumLength = aRestriction.GetMinimumLength();
+ if (aRestriction.HasFeature(Restriction.MaxLengthBit))
+ mnMaximumLength = aRestriction.GetMaximumLength();
+ }
+ else
+ {
+ // no restriction.
+ assert(aRestriction.GetFeatureBits() == 0);
+ }
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.println(toString());
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ final StringBuffer aBuffer = new StringBuffer();
+ aBuffer.append(String.format("string (%s)", meType));
+ if (maEnumerationValueIds != null)
+ {
+ aBuffer.append(" [");
+ boolean bIsFirst = true;
+ for (final String sValue : maEnumerationValues)
+ {
+ if (bIsFirst)
+ bIsFirst = false;
+ else
+ aBuffer.append(", ");
+ aBuffer.append(sValue);
+ }
+ aBuffer.append("]");
+ }
+ else if (maPattern != null)
+ {
+ aBuffer.append("pattern=\"");
+ aBuffer.append(maPattern);
+ aBuffer.append("\"");
+ }
+ return aBuffer.toString();
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ /** Try to join the called and the given string types.
+ * If that is possible then return the resulting type.
+ * Otherwise return null.
+ */
+ public ISimpleTypeNode Join (final StringNode aType)
+ {
+ if (maEnumerationValues!=null && aType.maEnumerationValues!=null)
+ {
+ // Join the enumeration values.
+ maEnumerationValues.addAll(aType.maEnumerationValues);
+ maEnumerationValueIds.addAll(aType.maEnumerationValueIds);
+ return this;
+ }
+ else
+ return null;
+ }
+
+
+ public enum RestrictionType
+ {
+ Pattern,
+ Enumeration,
+ Length,
+ None
+ }
+ public RestrictionType GetRestrictionType ()
+ {
+ if (maEnumerationValueIds != null)
+ return RestrictionType.Enumeration;
+ else if (maPattern != null)
+ return RestrictionType.Pattern;
+ else if (mnMinimumLength != null)
+ return RestrictionType.Length;
+ else
+ return RestrictionType.None;
+ }
+
+
+
+
+ public Set<Integer> GetEnumerationRestriction ()
+ {
+ final Set<Integer> aSortedIds = new TreeSet<>();
+ aSortedIds.addAll(maEnumerationValueIds);
+ return aSortedIds;
+ }
+
+
+
+
+ public String GetPatternRestriction ()
+ {
+ return msPattern;
+ }
+
+
+
+
+ public int[] GetLengthRestriction ()
+ {
+ return new int[]{mnMinimumLength, mnMaximumLength};
+ }
+
+
+
+
+ private boolean CheckLengthRestriction (
+ final String sValue,
+ final Restriction aRestriction)
+ {
+ final int nValueLength = sValue.length();
+ if (aRestriction.HasFeature(Restriction.LengthBit))
+ return nValueLength == aRestriction.GetLength();
+ else if (aRestriction.HasFeature(Restriction.MinLengthBit | Restriction.MaxLengthBit))
+ return nValueLength>=aRestriction.GetMinimumLength()
+ && nValueLength<=aRestriction.GetMaximumLength();
+ else if (aRestriction.HasFeature(Restriction.MinLengthBit))
+ return nValueLength>=aRestriction.GetMinimumLength();
+ else if (aRestriction.HasFeature(Restriction.MaxLengthBit))
+ return nValueLength<=aRestriction.GetMaximumLength();
+ else
+ throw new RuntimeException();
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ private final BuiltInType meType;
+ private Set<String> maEnumerationValues;
+ private Set<Integer> maEnumerationValueIds;
+ private Pattern maPattern;
+ private String msPattern;
+ private Integer mnMinimumLength;
+ private Integer mnMaximumLength;
+ private boolean mbIsList;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/UnionNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/UnionNode.java
new file mode 100644
index 000000000000..94d428ae333a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/UnionNode.java
@@ -0,0 +1,151 @@
+/**************************************************************
+*
+* 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.simple;
+
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class UnionNode
+ implements ISimpleTypeNode
+{
+ UnionNode ()
+ {
+ maTypes = new Vector<>();
+ mbIsList = false;
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aNode,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ throw new RuntimeException("can not handle restriction on union");
+ }
+
+
+
+
+
+ public void AddNode (final ISimpleTypeNode aType)
+ {
+ if (aType instanceof UnionNode)
+ {
+ // Integrate union of child into this union.
+ final UnionNode aChildUnion = (UnionNode)aType;
+ for (final ISimpleTypeNode aChildChild : aChildUnion.maTypes)
+ maTypes.add(aChildChild);
+ }
+ else if (aType instanceof StringNode)
+ {
+ // Is there already a string child?
+ for (int nIndex=0; nIndex<maTypes.size(); ++nIndex)
+ {
+ final ISimpleTypeNode aChild = maTypes.get(nIndex);
+
+ if (aChild instanceof StringNode)
+ {
+ // Yes. Can it be joined with the new child?
+ final ISimpleTypeNode aNewChild = ((StringNode)aChild).Join((StringNode)aType);
+ if (aNewChild != null)
+ {
+ // Yes. Replace the child with the joined child.
+ maTypes.set(nIndex, aNewChild);
+ return;
+ }
+ }
+ }
+ // When we reach this point then there was no join possible.
+ // Just add the new type.
+ maTypes.add(aType);
+
+ }
+ else
+ maTypes.add(aType);
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.printf("union of %d sub types\n", maTypes.size());
+ aLog.StartBlock();
+ for (final ISimpleTypeNode aType : maTypes)
+ aType.Print(aLog);
+ aLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "union";
+ }
+
+
+ ISimpleTypeNode[] GetChildren ()
+ {
+ return maTypes.toArray(new ISimpleTypeNode[maTypes.size()]);
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ private final Vector<ISimpleTypeNode> maTypes;
+ private boolean mbIsList;
+}