blob: a4ade948050c006fdb4c593b42eb5834955baeab [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.daffodil.dsom
import scala.xml.Node
import scala.xml.UnprefixedAttribute
import org.apache.daffodil.dsom.walker.RootView
import org.apache.daffodil.grammar.RootGrammarMixin
import org.apache.daffodil.xml.NamedQName
import org.apache.daffodil.xml.XMLUtils
object Root {
def apply(defXML: Node,
parentArg: SchemaDocument,
namedQNameArg: NamedQName,
globalElementDecl: GlobalElementDecl) = {
val r = new Root(defXML, parentArg, namedQNameArg, globalElementDecl)
r.initialize()
r
}
}
/**
* Root is a special kind of ElementRef that has no enclosing group.
*
* This is the entity that is compiled by the schema compiler.
*/
final class Root private (defXML: Node, parentArg: SchemaDocument,
namedQNameArg: NamedQName,
globalElementDecl: GlobalElementDecl)
extends AbstractElementRef(null, parentArg, 1)
with RootGrammarMixin
with RootView {
final override lazy val xml = {
val elem = XMLUtils.getXSDElement(defXML.scope)
val res = elem % new UnprefixedAttribute("ref", refQName.toQNameString, scala.xml.Null)
res
}
override lazy val refQName = namedQNameArg.toRefQName
override lazy val referencedElement = globalElementDecl
lazy val rootParseUnparsePolicy = defaultParseUnparsePolicy
/**
* For any given global schema component, tells us what schema components contain
* references to it, and if that reference is from a sequence or choice, the index of
* the group member within that sequence/choice.
*
* This is intended to be used when compilation needs to understand
* the context where an object is referenced. This allows the various referencing contexts
* to be known, without making copies of schema components for each such context.
*/
lazy val refMap: Map[GlobalComponent, Seq[(String, Seq[RefSpec])]] = {
val refEntries: Seq[(GlobalComponent, Seq[RefSpec])] =
refTargets.groupBy { _.to }.toSeq
val m: Seq[(GlobalComponent, Seq[(String, Seq[RefSpec])])] = refEntries.map {
case (to, seq) => (to, seq.groupBy { _.from.shortSchemaComponentDesignator }.toSeq)
}
m.toMap
}
final def elementRefsTo(decl: GlobalElementDecl): Seq[ElementRef] =
refsTo(decl).asInstanceOf[Seq[ElementRef]]
final def groupRefsTo(gdef: GlobalGroupDef): Seq[ModelGroup with GroupRef] =
refsTo(gdef).asInstanceOf[Seq[ModelGroup with GroupRef]]
private def refsTo(g: GlobalComponent): Seq[SchemaComponent] =
refMap.get(g).toSeq.flatMap { refSpec =>
refSpec.flatMap {
case (_, seqRS) =>
seqRS.map { rs: RefSpec => rs.from }
}
}
/**
* Used in unit testing
*/
private[dsom] lazy val refPairsMap: Map[GlobalComponent, Seq[String]] = {
refMap.toSeq.map {
case (to, seq: Seq[(String, _)]) => (to, seq.map { case (sscd, _) => sscd }.toSeq)
}.toMap
}
/*
* Important: the back-pointers allowing a shared object to know what is
* referencing it, those are constructed from this allComponents list.
* This implies that no reference to those things can occur in any
* computation needed to construct the allComponents list.
*
* So anything using the back-pointers (eg., enclosingComponents member)
* or anything derived from that, is effectively in a second pass that has to
* happen AFTER allComponents is computed.
*/
def allComponents = schemaSet.allSchemaComponents
final lazy val numComponents =
allComponents.length
final lazy val allComponentSSCDs =
allComponents.map { _.shortSchemaComponentDesignator }.distinct
final lazy val numUniqueComponents =
allComponentSSCDs.length
final lazy val refTargets: Seq[RefSpec] = {
allComponents.collect {
case ed: ElementDeclMixin => {
val optGSTD = ed.optNamedSimpleType.collect { case gstd: GlobalSimpleTypeDef => gstd }
val optNamedTypeDef = optGSTD ++ ed.optNamedComplexType
optNamedTypeDef.map { ntd => RefSpec(ed, ntd, 1) }.toSeq
}
case er: AbstractElementRef => {
val ed = er.referencedElement
RefSpec(er, ed, er.position) +:
ed.optNamedComplexType.map { gctd => RefSpec(ed, gctd, 1) }.toSeq
}
case gr: GroupRef => Seq(RefSpec(gr, gr.groupDef, gr.asModelGroup.position))
}.flatten
}
lazy val allERefs = allComponents.filter {
case er: ElementRef => true
case _ => false
}.map { _.shortSchemaComponentDesignator }.distinct
lazy val allGRefs = allComponents.filter {
case _: GroupRef => true
case _ => false
}.map { _.shortSchemaComponentDesignator }.distinct
lazy val allCTRefs = {
val cts = allComponents.collect {
case e: ElementDeclMixin if (
e.optComplexType.isDefined &&
e.complexType.isInstanceOf[GlobalComplexTypeDef]) =>
e.complexType
}
val ctsIDs = cts.map { _.shortSchemaComponentDesignator }.distinct
ctsIDs
}
}
case class RefSpec(from: SchemaComponent, to: GlobalComponent, index: Int) {
override def toString = "RefSpec(from=" +
from.shortSchemaComponentDesignator + ", to=" +
to.shortSchemaComponentDesignator + ", " + index +
")"
}