blob: b4ea4b18a555a0fd7e31cb179cbb08a5bd301b26 [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 org.apache.daffodil.exceptions.Assert
import scala.xml.Text
import scala.xml.Comment
object GlobalGroupDef {
def apply(defXML: Node, schemaDocument: SchemaDocument) = {
val trimmedXml = scala.xml.Utility.trim(defXML)
trimmedXml match {
case <group>{ contents @ _* }</group> => {
val list = contents.collect {
case groupXML @ <sequence>{ _* }</sequence> =>
GlobalSequenceGroupDef(defXML, groupXML, schemaDocument)
case groupXML @ <choice>{ _* }</choice> =>
GlobalChoiceGroupDef(defXML, groupXML, schemaDocument)
}
val res = list(0)
res
}
case _ => Assert.invariantFailed("not a group")
}
}
}
/**
* Common concepts for components that define groups.
*
* This includes both global group definitions, and local sequence
* and choice groups.
*/
trait GroupDefLike
extends AnnotatedSchemaComponent
with ProvidesDFDLStatementMixin {
/**
* Not named groupMembers to avoid confusion with ModelGroup.groupMembers.
*
* This is not necessarily a Term subclass, it is shared by global group definitions
* which are not terms. Non-terms don't deal with sharing the members.
* So this just provides them for sharing (as appropriate) by shared Terms.
*/
final def groupMembersNotShared = groupMembersDef
def xmlChildren: Seq[Node]
private lazy val goodXmlChildren = LV('goodXMLChildren) { xmlChildren.flatMap { removeNonInteresting(_) } }.value
/** Returns the group members that are elements or model groups. */
protected lazy val groupMembersDef: Seq[Term] = LV('groupMembers) {
computeGroupMembers()
}.value
// override in Choice
protected def computeGroupMembers(): Seq[Term] = {
val positions = List.range(1, goodXmlChildren.length + 1) // range is exclusive on 2nd arg. So +1.
val pairs = goodXmlChildren zip positions
val members = pairs.map {
case (n, i) =>
val t = TermFactory(n, this, i)
t
}
members
}
/**
* XML is full of uninteresting text nodes. We just want the element children, not all children.
*/
private def removeNonInteresting(child: Node) = {
val childElem: Option[Node] = child match {
case _: Text => None
case _: Comment => None
case <annotation>{ _* }</annotation> => None
case _ => Some(child)
}
childElem
}
}
/**
* Global Group Defs carry annotations that are combined with those
* of the corresponding group reference that refers to them.
*
* These are not carried on the xs:group element itself, but the xs:sequence
* or xs:choice XML child. When we refer to the annotations on a global group
* definition, we are referring to the annotations on the xs:sequence or xs:choice.
*/
sealed abstract class GlobalGroupDef(
defXML: Node,
groupXML: Node,
schemaDocumentArg: SchemaDocument)
extends AnnotatedSchemaComponentImpl(groupXML, schemaDocumentArg)
with GroupDefLike
with GlobalNonElementComponentMixin
with NestingLexicalMixin
with ResolvesLocalProperties // for dfdl:choiceBranchKey
{
def groupMembers = {
validateChoiceBranchKey()
this.groupMembersNotShared
}
private def validateChoiceBranchKey(): Unit = {
// Ensure the model group of a global group def do not define choiceBranchKey.
val found = findPropertyOption("choiceBranchKey")
if (found.isDefined) {
SDE("dfdl:choiceBranchKey cannot be specified on the choice/sequence child of a global group definition")
}
}
final override lazy val name = defXML.attribute("name").map { _.text }.getOrElse(
Assert.invariantFailed("Global group def without name attribute."))
override def optReferredToComponent = None
}
object GlobalSequenceGroupDef {
def apply(defXMLArg: Node, seqXML: Node, schemaDocument: SchemaDocument) = {
val gsgd = new GlobalSequenceGroupDef(defXMLArg, seqXML, schemaDocument)
gsgd.initialize()
gsgd
}
}
final class GlobalSequenceGroupDef private (
defXMLArg: Node, seqXML: Node, schemaDocument: SchemaDocument)
extends GlobalGroupDef(defXMLArg, seqXML, schemaDocument)
with SequenceDefMixin {
requiredEvaluationsIfActivated(checkGroupDefIsNotHiddenSequence)
private lazy val checkGroupDefIsNotHiddenSequence: Unit = {
if (hiddenGroupRefOption.isDefined) {
SDE("the model group of a group definition cannot be a sequence with dfdl:hiddenGroupRef")
}
}
}
object GlobalChoiceGroupDef {
def apply(defXMLArg: Node, xml: Node, schemaDocument: SchemaDocument) = {
val gsgd = new GlobalChoiceGroupDef(defXMLArg, xml, schemaDocument)
gsgd.initialize()
gsgd
}
}
final class GlobalChoiceGroupDef private (
defXMLArg: Node, choiceXML: Node, schemaDocument: SchemaDocument)
extends GlobalGroupDef(defXMLArg, choiceXML, schemaDocument)
with ChoiceDefMixin