| /* |
| * 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 |