You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by sl...@apache.org on 2020/07/17 11:25:10 UTC

[incubator-daffodil] branch master updated: Created an API for walking internal DSOM objects. This API is defined through a series of View Mixins that are implemented in various DSOM classes (their purpose is to give access to a select few properties in classes like ElementBase, Root, ModelGroup, etc) as well as an Abstract Walker class that, by default, recursively walks the DSOM and calls local event handlers in doing so. This Walker requires a RootView object to begin the traversal, which is now provided as an experimental memb [...]

This is an automated email from the ASF dual-hosted git repository.

slawrence pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-daffodil.git


The following commit(s) were added to refs/heads/master by this push:
     new 92d2036  Created an API for walking internal DSOM objects.  This API is defined through a series of View Mixins that are implemented in various DSOM classes (their purpose is to give access to a select few properties in classes like ElementBase, Root, ModelGroup, etc) as well as an Abstract Walker class that, by default, recursively walks the DSOM and calls local event handlers in doing so.  This Walker requires a RootView object to begin the traversal, which is now provided as a [...]
92d2036 is described below

commit 92d2036e3dfd818edf01843a5e5aa1117181712b
Author: Andrew Chafos <an...@gmail.com>
AuthorDate: Thu Jul 16 17:36:11 2020 -0400

    Created an API for walking internal DSOM objects.  This API is defined through a series of View Mixins that are implemented in various DSOM classes (their purpose is to give access to a select few properties in classes like ElementBase, Root, ModelGroup, etc) as well as an Abstract Walker class that, by default, recursively walks the DSOM and calls local event handlers in doing so.  This Walker requires a RootView object to begin the traversal, which is now provided as an experimental [...]
---
 .../org/apache/daffodil/compiler/Compiler.scala    |   4 +-
 .../org/apache/daffodil/dsom/ChoiceGroup.scala     |   5 +-
 .../org/apache/daffodil/dsom/ComplexTypes.scala    |   7 +-
 .../org/apache/daffodil/dsom/ElementBase.scala     |   6 +-
 .../apache/daffodil/dsom/ElementDeclMixin.scala    |  12 +-
 .../scala/org/apache/daffodil/dsom/GroupRef.scala  |   5 +-
 .../org/apache/daffodil/dsom/ModelGroup.scala      |   7 +-
 .../main/scala/org/apache/daffodil/dsom/Root.scala |   4 +-
 .../daffodil/dsom/SchemaComponentFactory.scala     |   6 +-
 .../org/apache/daffodil/dsom/SequenceGroup.scala   |   5 +-
 .../org/apache/daffodil/dsom/SimpleTypes.scala     |   7 +-
 .../main/scala/org/apache/daffodil/dsom/Term.scala |  10 +-
 .../daffodil/dsom/walker/AbstractDSOMWalker.scala  | 174 ++++++++++++++++++++
 .../apache/daffodil/dsom/walker/BasicWalker.scala  |  45 ++++++
 .../daffodil/dsom/walker/TestDSOMWalker.scala      | 177 +++++++++++++++++++++
 .../scala/org/apache/daffodil/japi/Daffodil.scala  |   8 +
 .../scala/org/apache/daffodil/dpath/NodeInfo.scala |  49 +++---
 .../apache/daffodil/dsom/walker/PrimTypeView.scala |  48 ++++++
 .../scala/org/apache/daffodil/sapi/Daffodil.scala  |   9 ++
 19 files changed, 541 insertions(+), 47 deletions(-)

diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/compiler/Compiler.scala b/daffodil-core/src/main/scala/org/apache/daffodil/compiler/Compiler.scala
index 290bed1..3c74654 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/compiler/Compiler.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/compiler/Compiler.scala
@@ -27,13 +27,13 @@ import java.util.zip.ZipException
 
 import scala.collection.immutable.Queue
 import scala.xml.Node
-
 import org.apache.daffodil.api.DFDL
 import org.apache.daffodil.api.DaffodilSchemaSource
 import org.apache.daffodil.api.DaffodilTunables
 import org.apache.daffodil.api.URISchemaSource
 import org.apache.daffodil.api.UnitTestSchemaSource
 import org.apache.daffodil.dsom.SchemaSet
+import org.apache.daffodil.dsom.walker.RootView
 import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.externalvars.Binding
 import org.apache.daffodil.externalvars.ExternalVariablesLoader
@@ -99,6 +99,8 @@ final class ProcessorFactory private(
       new SchemaSet(optRootSpec, schemaSource, validateDFDLSchemas, checkAllTopLevel, tunables,
         compilerExternalVarSettings))
 
+  lazy val rootView: RootView = sset.root
+
   def elementBaseInstanceCount = sset.elementBaseInstanceCount
 
   def diagnostics = sset.diagnostics
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ChoiceGroup.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ChoiceGroup.scala
index 0437712..35a90fd 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ChoiceGroup.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ChoiceGroup.scala
@@ -17,6 +17,8 @@
 
 package org.apache.daffodil.dsom
 
+import org.apache.daffodil.dsom.walker.ChoiceView
+
 import scala.xml.Node
 import scala.xml._
 import org.apache.daffodil.schema.annotation.props.gen.Choice_AnnotationMixin
@@ -243,7 +245,8 @@ abstract class ChoiceTermBase(
 
 final class Choice(xmlArg: Node, lexicalParent: SchemaComponent, position: Int)
   extends ChoiceTermBase(xmlArg, Option(lexicalParent), position)
-  with ChoiceDefMixin {
+  with ChoiceDefMixin
+  with ChoiceView {
 
   override lazy val optReferredToComponent = None
 
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ComplexTypes.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ComplexTypes.scala
index 7cf44bb..c5b9b9a 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ComplexTypes.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ComplexTypes.scala
@@ -20,13 +20,16 @@ package org.apache.daffodil.dsom
 import scala.xml.Node
 import org.apache.daffodil.dpath.NodeInfo
 import org.apache.daffodil.api.WarnID
+import org.apache.daffodil.dsom.walker.ComplexTypeView
+
 import scala.xml.Text
 import scala.xml.Comment
 
 sealed abstract class ComplexTypeBase(xmlArg: Node, parentArg: SchemaComponent)
   extends SchemaComponentImpl(xmlArg, parentArg)
   with TypeBase
-  with NonPrimTypeMixin {
+  with NonPrimTypeMixin
+  with ComplexTypeView {
 
   final override def optRestriction = None
   final override def optUnion = None
@@ -34,7 +37,7 @@ sealed abstract class ComplexTypeBase(xmlArg: Node, parentArg: SchemaComponent)
 
   requiredEvaluationsIfActivated(modelGroup)
 
-  final def group = modelGroup
+  override final def group = modelGroup
 
   /**
    * Convenience methods for unit testing. Just makes tests a bit more compact and clearer.
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
index d92e27c..a2dc4d9 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
@@ -34,6 +34,7 @@ import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.api.WarnID
 import java.lang.{Integer => JInt}
 
+import org.apache.daffodil.dsom.walker.ElementBaseView
 import org.apache.daffodil.infoset.DataValue
 import org.apache.daffodil.infoset.DataValue.DataValuePrimitiveOrUseNilForDefaultOrNull
 
@@ -63,7 +64,8 @@ trait ElementBase
   with TextNumberFormatMixin
   with EmptyElementParsePolicyMixin
   with TextStandardBaseMixin
-  with OverlapCheckMixin {
+  with OverlapCheckMixin
+  with ElementBaseView {
 
   override final def eBase = this
 
@@ -87,7 +89,7 @@ trait ElementBase
   requiredEvaluationsIfActivated(checkForAlignmentAmbiguity)
   requiredEvaluationsIfActivated(checkFloating)
 
-  def name: String
+  override def name: String
 
   final lazy val inputValueCalcOption = findPropertyOption("inputValueCalc")
 
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementDeclMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementDeclMixin.scala
index a57bac7..40598d0 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementDeclMixin.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementDeclMixin.scala
@@ -20,6 +20,7 @@ package org.apache.daffodil.dsom
 import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.xml._
 import org.apache.daffodil.dpath.NodeInfo.PrimType
+import org.apache.daffodil.dsom.walker.ElementDeclView
 import org.apache.daffodil.equality._
 import scala.xml.Node
 
@@ -42,19 +43,20 @@ trait ElementLikeMixin
  * Shared by all element declarations local or global
  */
 trait ElementDeclMixin
-  extends ElementLikeMixin {
+  extends ElementLikeMixin
+  with ElementDeclView {
 
-  final def isSimpleType: Boolean = optSimpleType.isDefined
+  override final def isSimpleType: Boolean = optSimpleType.isDefined
 
-  final def isComplexType = !isSimpleType
+  override final def isComplexType = !isSimpleType
 
   final def primType = optSimpleType.get.primType
 
   final def hasDefaultValue: Boolean = defaultAttr.isDefined
 
-  final def simpleType: SimpleTypeBase = optSimpleType.get
+  override final def simpleType: SimpleTypeBase = optSimpleType.get
 
-  final def complexType: ComplexTypeBase = optComplexType.get
+  override final def complexType: ComplexTypeBase = optComplexType.get
 
   /**
    * Convenience methods for unit testing purposes.
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/GroupRef.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/GroupRef.scala
index 02e7896..70341eb 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/GroupRef.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/GroupRef.scala
@@ -19,10 +19,11 @@ package org.apache.daffodil.dsom
 
 import scala.xml.Node
 import scala.xml._
+import org.apache.daffodil.dsom.walker.GroupRefView
 import org.apache.daffodil.xml.HasRefMixin
 import org.apache.daffodil.schema.annotation.props.NotFound
 
-trait GroupRef { self: ModelGroup =>
+trait GroupRef extends GroupRefView { self: ModelGroup =>
 
   final def asModelGroup: ModelGroup = self
 
@@ -33,7 +34,7 @@ trait GroupRef { self: ModelGroup =>
   /**
    * Override in sequenceGroupRef and choiceGroupRef for hidden groups
    */
-  def isHidden: Boolean
+  override def isHidden: Boolean
 
   final override lazy val optReferredToComponent = Some(referredToComponent)
 
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ModelGroup.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ModelGroup.scala
index b5712b2..0f11c62 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ModelGroup.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ModelGroup.scala
@@ -23,6 +23,8 @@ import scala.xml._
 import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.grammar.ModelGroupGrammarMixin
 import java.lang.{ Integer => JInt }
+
+import org.apache.daffodil.dsom.walker.ModelGroupView
 import org.apache.daffodil.schema.annotation.props.AlignmentType
 import org.apache.daffodil.schema.annotation.props.gen.AlignmentUnits
 import org.apache.daffodil.schema.annotation.props.gen.YesNo
@@ -135,7 +137,8 @@ abstract class ModelGroup(index: Int)
   extends Term
   with ModelGroupGrammarMixin
   with OverlapCheckMixin
-  with NestingLexicalMixin {
+  with NestingLexicalMixin
+  with ModelGroupView {
 
   requiredEvaluationsIfActivated(groupMembers)
   requiredEvaluationsIfActivated(initiatedContentCheck)
@@ -177,7 +180,7 @@ abstract class ModelGroup(index: Int)
    *
    * This also depends on groupMembersDef overrides all being lazy val.
    */
-  final lazy val groupMembers: Seq[Term] =
+  override final lazy val groupMembers: Seq[Term] =
     schemaSet.sharedGroupMembersFactory.getShared(shareKey, groupMembersDef)
 
   /**
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/Root.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/Root.scala
index fa9e734..23de673 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/Root.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/Root.scala
@@ -21,6 +21,7 @@ import scala.collection.mutable
 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
@@ -34,7 +35,8 @@ final class Root(defXML: Node, parentArg: SchemaDocument,
   namedQNameArg: NamedQName,
   globalElementDecl: GlobalElementDecl)
   extends AbstractElementRef(null, parentArg, 1)
-  with RootGrammarMixin {
+  with RootGrammarMixin
+  with RootView {
 
   requiredEvaluationsAlways({
     val ac = allComponents
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SchemaComponentFactory.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SchemaComponentFactory.scala
index 8760736..0e8e7f5 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SchemaComponentFactory.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SchemaComponentFactory.scala
@@ -17,8 +17,10 @@
 
 package org.apache.daffodil.dsom
 
+import org.apache.daffodil.dsom.walker.CommonContextView
 import org.apache.daffodil.exceptions.SchemaFileLocatable
 import org.apache.daffodil.xml.XMLUtils
+
 import scala.xml.NamespaceBinding
 import org.apache.daffodil.xml.NS
 
@@ -54,7 +56,7 @@ trait SchemaFileLocatableImpl
 }
 
 trait CommonContextMixin
-  extends NestingLexicalMixin { self: SchemaComponent =>
+  extends NestingLexicalMixin with CommonContextView { self: SchemaComponent =>
 
   def optLexicalParent: Option[SchemaComponent]
 
@@ -74,7 +76,7 @@ trait CommonContextMixin
    * in xsi:nil attributes, which is how we represent nilled elements
    * when we convert to XML.
    */
-  final lazy val namespaces = {
+  override final lazy val namespaces = {
     val scope = xml.scope
     val foundXsiURI = scope.getURI("xsi")
     val xsiURI = XMLUtils.xsiURI.toString
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SequenceGroup.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SequenceGroup.scala
index 0c4c0a7..e2ec844 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SequenceGroup.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SequenceGroup.scala
@@ -26,6 +26,7 @@ import org.apache.daffodil.xml.XMLUtils
 import org.apache.daffodil.schema.annotation.props.gen.OccursCountKind
 import org.apache.daffodil.schema.annotation.props.gen.SequenceKind
 import org.apache.daffodil.Implicits.ns2String
+import org.apache.daffodil.dsom.walker.SequenceView
 import org.apache.daffodil.grammar.SequenceGrammarMixin
 import org.apache.daffodil.schema.annotation.props.Found
 import org.apache.daffodil.schema.annotation.props.PropertyLookupResult
@@ -282,8 +283,8 @@ trait SequenceDefMixin
  */
 final class Sequence(xmlArg: Node, lexicalParent: SchemaComponent, position: Int)
   extends SequenceGroupTermBase(xmlArg, lexicalParent, position)
-  with SequenceDefMixin {
-
+  with SequenceDefMixin
+  with SequenceView {
 
   requiredEvaluationsIfActivated(checkHiddenGroupRefHasNoChildren)
 
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
index c6345a9..83e177a 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
@@ -17,7 +17,7 @@
 
 package org.apache.daffodil.dsom
 
-import java.math.{BigInteger => JBigInt}
+import java.math.{ BigInteger => JBigInt }
 
 import scala.xml.Node
 import org.apache.daffodil.cookers.IntRangeCooker
@@ -25,6 +25,7 @@ import org.apache.daffodil.cookers.RepValueCooker
 import org.apache.daffodil.dpath.NodeInfo
 import org.apache.daffodil.dpath.NodeInfo.PrimType
 import org.apache.daffodil.dpath.InvalidPrimitiveDataException
+import org.apache.daffodil.dsom.walker.SimpleTypeView
 import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.processors.IdentifyTypeCalculator
 import org.apache.daffodil.processors.RepValueSet
@@ -53,9 +54,9 @@ trait TypeBase {
 trait NonPrimTypeMixin
 
 sealed trait SimpleTypeBase extends TypeBase
-  with HasOptRepTypeMixin {
+  with HasOptRepTypeMixin with SimpleTypeView {
 
-  def primType: PrimType
+  override def primType: PrimType
 }
 
 /*
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/Term.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/Term.scala
index 7fae6e7..a500c08 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/Term.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/Term.scala
@@ -18,16 +18,19 @@
 package org.apache.daffodil.dsom
 
 import java.util.UUID
+
 import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.grammar.TermGrammarMixin
 import org.apache.daffodil.schema.annotation.props.gen.YesNo
 import java.lang.{ Integer => JInt }
+
 import org.apache.daffodil.schema.annotation.props.Found
 import org.apache.daffodil.schema.annotation.props.NotFound
 import org.apache.daffodil.schema.annotation.props.gen.LengthKind
 import org.apache.daffodil.schema.annotation.props.gen.OccursCountKind
 import org.apache.daffodil.schema.annotation.props.SeparatorSuppressionPolicy
 import org.apache.daffodil.api.WarnID
+import org.apache.daffodil.dsom.walker.TermView
 
 /**
  * Mixin for objects that are shared, but have consistency checks to be run
@@ -86,7 +89,8 @@ trait Term
   with DelimitedRuntimeValuedPropertiesMixin
   with InitiatedTerminatedMixin
   with TermEncodingMixin
-  with EscapeSchemeRefMixin {
+  with EscapeSchemeRefMixin
+  with TermView {
 
   requiredEvaluationsIfActivated(annotationObjs)
   requiredEvaluationsIfActivated(nonDefaultPropertySources)
@@ -178,7 +182,7 @@ trait Term
    *
    * The DFDL spec is not entirely consistent here either I don't believe.
    */
-  def isOptional: Boolean
+  override def isOptional: Boolean
 
   /**
    * An array can have more than 1 occurrence.
@@ -186,7 +190,7 @@ trait Term
    * An optional element (minOccurs=0, maxOccurs=1) is an array only
    * if occursCountKind is parsed, because then the max/min are ignored.
    */
-  def isArray: Boolean
+  override def isArray: Boolean
 
   def elementChildren: Seq[ElementBase]
 
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/walker/AbstractDSOMWalker.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/walker/AbstractDSOMWalker.scala
new file mode 100644
index 0000000..d45b88b
--- /dev/null
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/walker/AbstractDSOMWalker.scala
@@ -0,0 +1,174 @@
+/*
+ * 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.walker
+
+/**
+ * Below is a series of "View" Mixins defined such that particular simple attributes
+ * of the core DSOM classes are exposed as a Walk is performed.
+ *
+ * Several of them have a walkDSOM method.  By default, this method is called as the walk is performed,
+ * but a user implementing AbstractDSOMWalker can override this behavior by overriding walkFromRoot
+ * and implementing their own event handlers for each of the DSOM types.
+ */
+
+trait CommonContextView {
+  def namespaces: scala.xml.NamespaceBinding
+}
+
+trait TermView extends CommonContextView {
+  def isArray: Boolean
+  def isOptional: Boolean
+}
+
+trait TypeView
+trait SimpleTypeView extends TypeView {
+  def primType: PrimTypeView
+}
+trait ComplexTypeView extends TypeView {
+  def group: ModelGroupView
+}
+
+trait ModelGroupView extends TermView {
+  def groupMembers: Seq[TermView]
+}
+
+trait ChoiceView extends ModelGroupView
+trait SequenceView extends ModelGroupView
+trait GroupRefView extends ModelGroupView {
+  def isHidden: Boolean
+}
+
+trait ElementDeclView extends CommonContextView {
+  def isSimpleType: Boolean
+  def isComplexType: Boolean
+  def simpleType: SimpleTypeView
+  def complexType: ComplexTypeView
+}
+
+trait ElementBaseView extends ElementDeclView with TermView {
+  def name: String
+}
+
+trait RootView extends ElementBaseView
+
+/**
+ * A class designed to walk the internal representation of a DFDL Schema File.
+ *
+ * There are 2 main event handlers an implementing class has to worry about: one for Terms, and
+ * another for Types.  These are called as the DSOM is walked.
+ *
+ * Though recursion is used here to define the walk, it is not advised to use recursion between
+ * these event handlers.  Instead, consider a stack-like structure, as the DFDL Schema structure
+ * as well as the recursive method call structure can be represented by trees.
+ */
+abstract class AbstractDSOMWalker {
+
+  /**
+   * Method to be called on the beginning of the traversal.  It is recommended to add some
+   * sort of wrapper element to a stack if you're doing a typical stack-based traversal.
+   *
+   * @param root the root element of the DFDL Schema
+   */
+  protected def onWalkBegin(root: RootView): Unit
+
+  /**
+   * Method to be called when the traversal concludes.  It is recommended to put any post-processing
+   * and anything to tidy up the stack or the result here.
+   *
+   * @param root the root element of the DFDL Schema
+   */
+  protected def onWalkEnd(root: RootView): Unit
+
+  /**
+   * Method to be called whenever any element that is a Term is encountered.
+   * This applies to Sequence, Choice, GroupRef, ElementBase, etc.
+   *
+   * It is highly recommended that, when implementing this method, you pattern match
+   * some of these different sub-types at some point to handle each accordingly.
+   *
+   * @param termElement the term element
+   */
+  def onTermBegin(termElement: TermView): Unit
+
+  /**
+   * Method to be called when a Term element has finished processing
+   *
+   * @param termElement the term element
+   */
+  def onTermEnd(termElement: TermView): Unit
+
+  /**
+   * Method to be called when either a Simple or Complex Type element has been encountered.
+   * This is just the element for <simpleType> or <complexType>, so no implementation is necessary if you
+   * do not care about these wrapper portion; its children will be walked automatically.
+   *
+   * @param typeElement either a Simple or Complex type
+   */
+  def onTypeBegin(typeElement: TypeView): Unit
+
+  /**
+   * Method to be called when either a Simple or Complex Type element has been finished
+   * processing.  See onTypeBegin method description
+   *
+   * @param typeElement either a Simple or Complex type
+   */
+  def onTypeEnd(typeElement: TypeView): Unit
+
+  /**
+   * Starts a DSOM walk from the Root object.  By default, the walk is completed recursively in the helper
+   * method below, but a custom walk can be defined by overriding
+   * this method instead and calling local event handlers.
+   * @param schemaSetRoot The root element of the DFDL Schema.  This will be the starting point of the traversal
+   */
+  def walkFromRoot(schemaSetRoot: RootView): Unit = {
+    onWalkBegin(schemaSetRoot)
+    walkerHelper(schemaSetRoot)
+    onWalkEnd(schemaSetRoot)
+  }
+
+  /**
+   * Local helper method used to recursively walk the DSOM.
+   * If a non-recursive walk or a more specific recursive walk is desired, one
+   * can override this method, or simply not use it and instead override walkFromRoot
+   * and have that overridden method reference custom helper methods.
+   * @param termView the current Term element to be pattern matched
+   */
+  protected def walkerHelper(termView: TermView): Unit = {
+    onTermBegin(termView)
+    termView match {
+      case element: ElementBaseView =>
+        if (element.isComplexType) {
+          onTypeBegin(element.complexType)
+          walkerHelper(element.complexType.group)
+          onTypeEnd(element.complexType)
+        } else {
+          onTypeBegin(element.simpleType)
+          onTypeEnd(element.simpleType)
+        }
+      case groupRef: GroupRefView =>
+        if (!groupRef.isHidden) {
+          groupRef.groupMembers.foreach(walkerHelper)
+        }
+      case modelGroup: ModelGroupView =>
+        modelGroup.groupMembers.foreach(walkerHelper)
+    }
+    onTermEnd(termView)
+  }
+
+
+}
\ No newline at end of file
diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/dsom/walker/BasicWalker.scala b/daffodil-core/src/test/scala/org/apache/daffodil/dsom/walker/BasicWalker.scala
new file mode 100644
index 0000000..7259f9a
--- /dev/null
+++ b/daffodil-core/src/test/scala/org/apache/daffodil/dsom/walker/BasicWalker.scala
@@ -0,0 +1,45 @@
+/*
+ * 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.walker
+
+import scala.collection.mutable.ArrayBuffer
+
+class BasicWalker(ignoreTypeWrappers: Boolean = false, onlyElements: Boolean = false, ignoreEndEvents: Boolean = true) extends AbstractDSOMWalker {
+
+  var nodeArr: ArrayBuffer[AnyRef] = ArrayBuffer()
+
+  private def addViewElement(viewElement: AnyRef): Unit = {
+    viewElement match {
+      case _: ElementBaseView => nodeArr += viewElement
+      case _: TermView => if (!onlyElements) nodeArr += viewElement
+      case _ => if (!ignoreTypeWrappers) nodeArr += viewElement
+    }
+  }
+
+  override protected def onWalkBegin(root: RootView): Unit = addViewElement(root)
+
+  override protected def onWalkEnd(root: RootView): Unit = if (!ignoreEndEvents) addViewElement(root)
+
+  override def onTermBegin(termElement: TermView): Unit = addViewElement(termElement)
+
+  override def onTermEnd(termElement: TermView): Unit = if (!ignoreEndEvents) addViewElement(termElement)
+
+  override def onTypeBegin(typeElement: TypeView): Unit = addViewElement(typeElement)
+
+  override def onTypeEnd(typeElement: TypeView): Unit = if (!ignoreEndEvents) addViewElement(typeElement)
+}
diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/dsom/walker/TestDSOMWalker.scala b/daffodil-core/src/test/scala/org/apache/daffodil/dsom/walker/TestDSOMWalker.scala
new file mode 100644
index 0000000..5fb2724
--- /dev/null
+++ b/daffodil-core/src/test/scala/org/apache/daffodil/dsom/walker/TestDSOMWalker.scala
@@ -0,0 +1,177 @@
+/*
+ * 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.walker
+
+import org.apache.daffodil.util._
+import org.apache.daffodil.compiler.{ Compiler, ProcessorFactory }
+import org.junit.Test
+import org.junit.Assert._
+
+class TestDSOMWalker {
+
+  @Test def testComplexTypesAndEndEvents(): Unit = {
+    val testSchema = SchemaUtils.dfdlTestSchema(
+      <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>,
+      <dfdl:format ref="ex:GeneralFormat"
+                   alignment="implicit" alignmentUnits="bits" occursCountKind="implicit"
+                   lengthKind="delimited" encoding="ASCII"/>,
+      <xs:element name="PersonData">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:choice>
+              <xs:element name="age" type="xs:int" minOccurs="1" maxOccurs="1"/>
+            </xs:choice>
+            <xs:group ref="testGroup" />
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:group name="testGroup">
+        <xs:sequence />
+      </xs:group>
+    )
+    val pf: ProcessorFactory = Compiler().compileNode(testSchema)
+    assertEquals(s"This basic Schema: $testSchema should compile; here are some diagnostics: ${pf.getDiagnostics}", false, pf.isError)
+    val walker: BasicWalker = new BasicWalker(ignoreEndEvents = false)
+    walker.walkFromRoot(pf.rootView)
+    val nodeStack: List[AnyRef] = walker.nodeArr.toList
+    assertEquals(s"Node Stack $nodeStack should have 16 elements", 16, nodeStack.size)
+    assertTrue("Should have received a start event for the overall traversal", nodeStack.head.isInstanceOf[RootView])
+    assertTrue("The Root element was not of type RootView", nodeStack(1).isInstanceOf[RootView])
+    assertEquals("The root element should be named 'PersonData'", "PersonData", nodeStack(1).asInstanceOf[RootView].name)
+    assertTrue("The root element should contain a complexType wrapper child", nodeStack(2).isInstanceOf[ComplexTypeView])
+    assertTrue("The complexType element should contain a Sequence child", nodeStack(3).isInstanceOf[SequenceView])
+    assertTrue("The Sequence element should contain a Choice child", nodeStack(4).isInstanceOf[ChoiceView])
+    assertTrue("The Choice element should contain an Element child", nodeStack(5).isInstanceOf[ElementBaseView])
+    assertEquals("The Element child should be named 'age'", "age", nodeStack(5).asInstanceOf[ElementBaseView].name)
+    assertEquals("The Element child should be a simple type", true, nodeStack(5).asInstanceOf[ElementBaseView].isSimpleType)
+    assertTrue("The 'age' element should have a SimpleTypeView", nodeStack(6).isInstanceOf[SimpleTypeView])
+    assertTrue("Should have received an end event for the Simple Type", nodeStack(7).isInstanceOf[SimpleTypeView])
+    assertTrue("Should have received an end event for the 'age' element", nodeStack(8).isInstanceOf[ElementBaseView])
+    assertTrue("Should have received an end event for the Choice element", nodeStack(9).isInstanceOf[ChoiceView])
+    assertTrue("The Sequence element should contain a second child that is a GroupRef", nodeStack(10).isInstanceOf[GroupRefView])
+    assertTrue("Should have received an end event for the GroupRef element", nodeStack(11).isInstanceOf[GroupRefView])
+    assertTrue("Should have received an end event for the Sequence element", nodeStack(12).isInstanceOf[SequenceView])
+    assertTrue("Should have received an end event for the complexType wrapper element", nodeStack(13).isInstanceOf[ComplexTypeView])
+    assertTrue("Should have received an end event for the Root element", nodeStack(14).isInstanceOf[RootView])
+    assertTrue("Should have received an end event for the overall traversal", nodeStack(15).isInstanceOf[RootView])
+  }
+
+  private def getSuffix(ordinal: Int): String = {
+    if ((ordinal % 100) / 10 == 1) "th"
+    else if (ordinal % 10 == 1) "st"
+    else if (ordinal % 10 == 2) "nd"
+    else if (ordinal % 10 == 3) "rd"
+    else "th"
+  }
+
+  @Test def testAllSimpleTypes(): Unit = {
+    val testSchema = SchemaUtils.dfdlTestSchema(
+      <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>,
+      <dfdl:format ref="ex:GeneralFormat"
+                   alignment="implicit" alignmentUnits="bits" occursCountKind="implicit"
+                   lengthKind="implicit" encoding="ASCII"/>,
+      <xs:element name="AllSimples">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="stringField" type="xs:string" minOccurs="1" maxOccurs="1" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="booleanField" type="xs:boolean" dfdl:lengthKind="explicit" dfdl:length="1" dfdl:textBooleanTrueRep="1" dfdl:textBooleanFalseRep="0" />
+            <xs:element name="byteField" type="xs:byte" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="shortField" type="xs:short" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="intField" type="xs:int" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="longField" type="xs:long" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="unsignedByteField" type="xs:unsignedByte" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="unsignedShortField" type="xs:unsignedShort" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="unsignedIntField" type="xs:unsignedInt" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="unsignedLongField" type="xs:unsignedLong" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="nonNegativeIntegerField" type="xs:nonNegativeInteger" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="integerField" type="xs:integer" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="floatField" type="xs:float" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="doubleField" type="xs:double" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="decimalField" type="xs:decimal" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="hexBinaryField" type="xs:hexBinary" dfdl:lengthKind="explicit" dfdl:length="1"/>
+            <xs:element name="anyURIField" type="xs:anyURI" dfdl:lengthKind="explicit" dfdl:length="1" dfdlx:objectKind="bytes"/>
+            <xs:element name="dateTimeField" type="xs:dateTime" dfdl:calendarPattern="yyyy.MM.dd G 'at' HH:mm:ss ZZZZ"
+                        dfdl:calendarPatternKind="explicit" dfdl:lengthKind="explicit" dfdl:length="35"/>
+            <xs:element name="dateField" type="xs:date" dfdl:calendarPattern="EEEE, MMM d, ''yy" dfdl:calendarPatternKind="explicit"
+                        dfdl:lengthKind="explicit" dfdl:length="23"/>
+            <xs:element name="timeField" type="xs:time" dfdl:calendarPattern="h:mm a" dfdl:calendarPatternKind="explicit"
+                        dfdl:lengthKind="explicit" dfdl:length="8"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    )
+    val pf: ProcessorFactory = Compiler().compileNode(testSchema)
+    assertEquals(s"This basic Schema $testSchema should compile; here are some diagnostics: ${pf.getDiagnostics}", false, pf.isError)
+    val walker: BasicWalker = new BasicWalker(false, true)
+    walker.walkFromRoot(pf.rootView)
+    val simpleTypes: List[Class[_ <: PrimTypeView]] = List(
+      classOf[StringView], classOf[BooleanView], classOf[ByteView], classOf[ShortView], classOf[IntView],
+      classOf[LongView], classOf[UnsignedByteView], classOf[UnsignedShortView], classOf[UnsignedIntView], classOf[UnsignedLongView],
+      classOf[NonNegativeIntegerView], classOf[IntegerView], classOf[FloatView], classOf[DoubleView], classOf[DecimalView],
+      classOf[HexBinaryView], classOf[AnyURIView], classOf[DateTimeView], classOf[DateView], classOf[TimeView]
+    )
+    val nodeStack: List[AnyRef] = walker.nodeArr.toList
+    assertEquals(s"Node Stack $nodeStack did not have the expected number of elements", 2 * simpleTypes.size + 3, nodeStack.size)
+    for (index <- 1 to simpleTypes.size) {
+      val elementIndex = 2 * index + 1
+      val simpleTypeIndex = 2 * index + 2
+      assertTrue(s"The $elementIndex${getSuffix(elementIndex)} element in the stack should be an Element", nodeStack(elementIndex).isInstanceOf[ElementBaseView])
+      val className: String = simpleTypes(index - 1).getSimpleName
+      val withoutView: String = className.substring(0, className.length - 4)
+      val fieldName: String = withoutView.charAt(0).toLower + withoutView.substring(1) + "Field"
+      assertEquals(
+        s"The $elementIndex${getSuffix(elementIndex)} element in the stack should be named '$fieldName'", fieldName,
+        nodeStack(elementIndex).asInstanceOf[ElementBaseView].name
+      )
+      assertTrue(
+        s"The $simpleTypeIndex${getSuffix(simpleTypeIndex)} element in the stack should be a Simple type",
+        nodeStack(simpleTypeIndex).isInstanceOf[SimpleTypeView]
+      )
+      assertTrue(
+        s"The $simpleTypeIndex${getSuffix(simpleTypeIndex)} element in the stack should be of type '$className'",
+        simpleTypes(index - 1).isInstance(nodeStack(simpleTypeIndex).asInstanceOf[SimpleTypeView].primType)
+      )
+    }
+  }
+
+  @Test def testOptionalField(): Unit = {
+    val testSchema = SchemaUtils.dfdlTestSchema(
+      <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>,
+      <dfdl:format ref="ex:GeneralFormat"
+                   alignment="implicit" alignmentUnits="bits" occursCountKind="implicit"
+                   lengthKind="delimited" encoding="ASCII"/>,
+      <xs:element name="DataList">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="data" type="xs:string" minOccurs="0" maxOccurs="1"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    )
+    val pf: ProcessorFactory = Compiler().compileNode(testSchema)
+    assertEquals(s"This basic Schema: $testSchema should compile; here are some diagnostics: ${pf.getDiagnostics}", false, pf.isError)
+    val walker: BasicWalker = new BasicWalker(true, true)
+    walker.walkFromRoot(pf.rootView)
+    val nodeStack: List[AnyRef] = walker.nodeArr.toList
+    assertEquals(s"Node Stack $nodeStack did not have the expected number of elements", 3, nodeStack.size)
+    assertTrue("The 3rd element in the stack should be an Element", nodeStack(2).isInstanceOf[ElementBaseView])
+    assertEquals("The 3rd element in the stack should be named 'data'", "data", nodeStack(2).asInstanceOf[ElementBaseView].name)
+    assertEquals("The 'data' element should be optional", true, nodeStack(2).asInstanceOf[ElementBaseView].isOptional)
+  }
+
+}
diff --git a/daffodil-japi/src/main/scala/org/apache/daffodil/japi/Daffodil.scala b/daffodil-japi/src/main/scala/org/apache/daffodil/japi/Daffodil.scala
index 930ba69..3feca34 100644
--- a/daffodil-japi/src/main/scala/org/apache/daffodil/japi/Daffodil.scala
+++ b/daffodil-japi/src/main/scala/org/apache/daffodil/japi/Daffodil.scala
@@ -48,6 +48,7 @@ import org.apache.daffodil.util.{ NullLogWriter => SNullLogWriter }
 import org.apache.daffodil.externalvars.Binding
 import org.apache.daffodil.externalvars.ExternalVariablesLoader
 import org.apache.daffodil.dsom.ExpressionCompilers
+import org.apache.daffodil.dsom.walker.RootView
 import org.apache.daffodil.compiler.{ InvalidParserException => SInvalidParserException }
 import org.apache.daffodil.processors.{ InvalidUsageException => SInvalidUsageException }
 import java.net.URI
@@ -373,6 +374,13 @@ class ProcessorFactory private[japi] (private var pf: SProcessorFactory)
     new DataProcessor(dp)
   }
 
+  class ExperimentalWrapper(val rootView: RootView)
+  /**
+   * Exposes the RootView object corresponding to this ProcessorFactory.  This can
+   * be used to start a walk using the walkFromRoot method in a DSOM Walker.
+   */
+  lazy val experimental: ExperimentalWrapper = new ExperimentalWrapper(pf.rootView)
+
 }
 
 /**
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/NodeInfo.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/NodeInfo.scala
index 86876c6..e6e0561 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/NodeInfo.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/NodeInfo.scala
@@ -26,6 +26,7 @@ import org.apache.daffodil.calendar.DFDLCalendar
 import org.apache.daffodil.calendar.DFDLDateConversion
 import org.apache.daffodil.calendar.DFDLDateTimeConversion
 import org.apache.daffodil.calendar.DFDLTimeConversion
+import org.apache.daffodil.dsom.walker._
 import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.infoset.DataValue.DataValueBigDecimal
 import org.apache.daffodil.infoset.DataValue.DataValueBigInt
@@ -165,7 +166,7 @@ object NodeInfo extends Enum {
     }
   }
 
-  sealed trait Kind extends EnumValueType {
+  sealed trait Kind extends EnumValueType with PrimTypeView {
     def name: String = Misc.getNameFromClass(this)
 
     def parents: Seq[Kind]
@@ -546,7 +547,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait FloatKind extends SignedNumeric.Kind
-    case object Float extends PrimTypeNode(SignedNumeric) with FloatKind with PrimNumericFloat {
+    case object Float extends PrimTypeNode(SignedNumeric) with FloatKind with PrimNumericFloat with FloatView {
       type Kind = FloatKind
       protected override def fromString(s: String) = {
         val f: JFloat = s match {
@@ -563,7 +564,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait DoubleKind extends SignedNumeric.Kind
-    case object Double extends PrimTypeNode(SignedNumeric) with DoubleKind with PrimNumericFloat {
+    case object Double extends PrimTypeNode(SignedNumeric) with DoubleKind with PrimNumericFloat with DoubleView {
       type Kind = DoubleKind
       protected override def fromString(s: String): DataValueDouble = {
         val d: JDouble = s match {
@@ -580,7 +581,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait DecimalKind extends SignedNumeric.Kind
-    case object Decimal extends PrimTypeNode(SignedNumeric, List(Integer)) with DecimalKind with PrimNumeric {
+    case object Decimal extends PrimTypeNode(SignedNumeric, List(Integer)) with DecimalKind with PrimNumeric with DecimalView {
       type Kind = DecimalKind
       protected override def fromString(s: String): DataValueBigDecimal = new JBigDecimal(s)
       protected override def fromNumberNoCheck(n: Number): DataValueBigDecimal = asBigDecimal(n)
@@ -588,7 +589,8 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait IntegerKind extends Decimal.Kind
-    case object Integer extends PrimTypeNode(Decimal, List(Long, NonNegativeInteger)) with IntegerKind with PrimNumeric {
+    case object Integer extends PrimTypeNode(Decimal, List(Long, NonNegativeInteger)) with IntegerKind with PrimNumeric
+        with IntegerView {
       type Kind = IntegerKind
       protected override def fromString(s: String): DataValueBigInt = new JBigInt(s)
       protected override def fromNumberNoCheck(n: Number): DataValueBigInt = asBigInt(n)
@@ -596,7 +598,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait LongKind extends Integer.Kind
-    case object Long extends PrimTypeNode(Integer, List(Int)) with LongKind with PrimNumericInteger {
+    case object Long extends PrimTypeNode(Integer, List(Int)) with LongKind with PrimNumericInteger with LongView {
       type Kind = LongKind
       protected override def fromString(s: String): DataValueLong = s.toLong
       protected override def fromNumberNoCheck(n: Number): DataValueLong = n.longValue
@@ -605,7 +607,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait IntKind extends Long.Kind
-    case object Int extends PrimTypeNode(Long, List(Short)) with IntKind with PrimNumericInteger {
+    case object Int extends PrimTypeNode(Long, List(Short)) with IntKind with PrimNumericInteger with IntView {
       type Kind = IntKind
       protected override def fromString(s: String): DataValueInt = s.toInt
       protected override def fromNumberNoCheck(n: Number): DataValueInt = n.intValue
@@ -614,7 +616,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait ShortKind extends Int.Kind
-    case object Short extends PrimTypeNode(Int, List(Byte)) with ShortKind with PrimNumericInteger {
+    case object Short extends PrimTypeNode(Int, List(Byte)) with ShortKind with PrimNumericInteger with ShortView {
       type Kind = ShortKind
       protected override def fromString(s: String): DataValueShort = s.toShort
       protected override def fromNumberNoCheck(n: Number): DataValueShort = n.shortValue
@@ -623,7 +625,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait ByteKind extends Short.Kind
-    case object Byte extends PrimTypeNode(Short) with ByteKind with PrimNumericInteger {
+    case object Byte extends PrimTypeNode(Short) with ByteKind with PrimNumericInteger with ByteView {
       type Kind = ByteKind
       protected override def fromString(s: String): DataValueByte = s.toByte
       protected override def fromNumberNoCheck(n: Number): DataValueByte = n.byteValue
@@ -632,7 +634,8 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait NonNegativeIntegerKind extends Integer.Kind
-    case object NonNegativeInteger extends PrimTypeNode(Integer, List(UnsignedLong)) with NonNegativeIntegerKind with PrimNumeric {
+    case object NonNegativeInteger extends PrimTypeNode(Integer, List(UnsignedLong)) with NonNegativeIntegerKind with PrimNumeric
+        with NonNegativeIntegerView {
       type Kind = NonNegativeIntegerKind
       protected override def fromString(s: String): DataValueBigInt = new JBigInt(s)
       protected override def fromNumberNoCheck(n: Number): DataValueBigInt = asBigInt(n)
@@ -643,7 +646,8 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait UnsignedLongKind extends NonNegativeInteger.Kind
-    case object UnsignedLong extends PrimTypeNode(NonNegativeInteger, List(UnsignedInt)) with UnsignedLongKind with PrimNumeric {
+    case object UnsignedLong extends PrimTypeNode(NonNegativeInteger, List(UnsignedInt)) with UnsignedLongKind with PrimNumeric
+        with UnsignedLongView {
       type Kind = UnsignedLongKind
       protected override def fromString(s: String): DataValueBigInt = new JBigInt(s)
       protected override def fromNumberNoCheck(n: Number): DataValueBigInt = asBigInt(n)
@@ -657,7 +661,8 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait UnsignedIntKind extends UnsignedLong.Kind
-    case object UnsignedInt extends PrimTypeNode(UnsignedLong, List(UnsignedShort, ArrayIndex)) with UnsignedIntKind with PrimNumericInteger {
+    case object UnsignedInt extends PrimTypeNode(UnsignedLong, List(UnsignedShort, ArrayIndex)) with UnsignedIntKind with PrimNumericInteger
+        with UnsignedIntView {
       type Kind = UnsignedIntKind
       protected override def fromString(s: String): DataValueLong = s.toLong
       protected override def fromNumberNoCheck(n: Number): DataValueLong = n.longValue
@@ -666,7 +671,8 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait UnsignedShortKind extends UnsignedInt.Kind
-    case object UnsignedShort extends PrimTypeNode(UnsignedInt, List(UnsignedByte)) with UnsignedShortKind with PrimNumericInteger {
+    case object UnsignedShort extends PrimTypeNode(UnsignedInt, List(UnsignedByte)) with UnsignedShortKind with PrimNumericInteger
+        with UnsignedShortView {
       type Kind = UnsignedShortKind
       protected override def fromString(s: String): DataValueInt = s.toInt
       protected override def fromNumberNoCheck(n: Number): DataValueInt = n.intValue
@@ -675,7 +681,8 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait UnsignedByteKind extends UnsignedShort.Kind
-    case object UnsignedByte extends PrimTypeNode(UnsignedShort) with UnsignedByteKind with PrimNumericInteger {
+    case object UnsignedByte extends PrimTypeNode(UnsignedShort) with UnsignedByteKind with PrimNumericInteger
+        with UnsignedByteView {
       type Kind = UnsignedByteKind
       protected override def fromString(s: String): DataValueShort = s.toShort
       protected override def fromNumberNoCheck(n: Number): DataValueShort = n.shortValue
@@ -684,31 +691,31 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait StringKind extends AnyAtomic.Kind
-    case object String extends PrimTypeNode(AnyAtomic, List(NonEmptyString)) with StringKind {
+    case object String extends PrimTypeNode(AnyAtomic, List(NonEmptyString)) with StringKind with StringView {
       type Kind = StringKind
       override def fromXMLString(s: String) = s
     }
 
     protected sealed trait BooleanKind extends AnySimpleType.Kind
-    case object Boolean extends PrimTypeNode(AnyAtomic) with BooleanKind with PrimNonNumeric {
+    case object Boolean extends PrimTypeNode(AnyAtomic) with BooleanKind with PrimNonNumeric with BooleanView {
       type Kind = BooleanKind
       protected override def fromString(s: String): DataValueBool = s.toBoolean
     }
 
     protected sealed trait AnyURIKind extends AnySimpleType.Kind
-    case object AnyURI extends PrimTypeNode(AnyAtomic) with AnyURIKind with PrimNonNumeric {
+    case object AnyURI extends PrimTypeNode(AnyAtomic) with AnyURIKind with PrimNonNumeric with AnyURIView {
       type Kind = AnyURIKind
       protected override def fromString(s: String): DataValueURI = new URI(s)
     }
 
     protected sealed trait HexBinaryKind extends Opaque.Kind
-    case object HexBinary extends PrimTypeNode(Opaque) with HexBinaryKind with PrimNonNumeric {
+    case object HexBinary extends PrimTypeNode(Opaque) with HexBinaryKind with PrimNonNumeric with HexBinaryView {
       type Kind = HexBinaryKind
       protected override def fromString(s: String): DataValueByteArray = Misc.hex2Bytes(s)
     }
 
     protected sealed trait DateKind extends AnyDateTimeKind
-    case object Date extends PrimTypeNode(AnyDateTime) with DateKind with PrimNonNumeric {
+    case object Date extends PrimTypeNode(AnyDateTime) with DateKind with PrimNonNumeric with DateView {
       type Kind = DateKind
       protected override def fromString(s: String): DataValueDate = {
         DFDLDateConversion.fromXMLString(s)
@@ -716,7 +723,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait DateTimeKind extends AnyDateTimeKind
-    case object DateTime extends PrimTypeNode(AnyDateTime) with DateTimeKind with PrimNonNumeric {
+    case object DateTime extends PrimTypeNode(AnyDateTime) with DateTimeKind with PrimNonNumeric with DateTimeView {
       type Kind = DateTimeKind
       protected override def fromString(s: String): DataValueDateTime = {
         DFDLDateTimeConversion.fromXMLString(s)
@@ -724,7 +731,7 @@ object NodeInfo extends Enum {
     }
 
     protected sealed trait TimeKind extends AnyDateTimeKind
-    case object Time extends PrimTypeNode(AnyDateTime) with TimeKind with PrimNonNumeric {
+    case object Time extends PrimTypeNode(AnyDateTime) with TimeKind with PrimNonNumeric with TimeView {
       type Kind = TimeKind
       protected override def fromString(s: String): DataValueTime = {
         DFDLTimeConversion.fromXMLString(s)
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dsom/walker/PrimTypeView.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dsom/walker/PrimTypeView.scala
new file mode 100644
index 0000000..13e6e34
--- /dev/null
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dsom/walker/PrimTypeView.scala
@@ -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.daffodil.dsom.walker
+
+/**
+ * This is a series of View Mixins similar to the ones defined in AbstractDSOMWalker.
+ * Since these traits don't have any attributes, their only purpose is for pattern matching
+ * simple types during a walk.
+ *
+ * They had to be defined in runtime-1 because all of the PrimType enums in NodeInfo extend them,
+ * and NodeInfo is part of runtime-1.
+ */
+
+trait PrimTypeView
+trait StringView extends PrimTypeView
+trait BooleanView extends PrimTypeView
+trait ByteView extends PrimTypeView
+trait ShortView extends PrimTypeView
+trait IntView extends PrimTypeView
+trait LongView extends PrimTypeView
+trait UnsignedByteView extends PrimTypeView
+trait UnsignedShortView extends PrimTypeView
+trait UnsignedIntView extends PrimTypeView
+trait UnsignedLongView extends PrimTypeView
+trait NonNegativeIntegerView extends PrimTypeView
+trait IntegerView extends PrimTypeView
+trait FloatView extends PrimTypeView
+trait DoubleView extends PrimTypeView
+trait DecimalView extends PrimTypeView
+trait HexBinaryView extends PrimTypeView
+trait AnyURIView extends PrimTypeView
+trait DateTimeView extends PrimTypeView
+trait DateView extends PrimTypeView
+trait TimeView extends PrimTypeView
\ No newline at end of file
diff --git a/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/Daffodil.scala b/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/Daffodil.scala
index 42e6a06..35b0016 100644
--- a/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/Daffodil.scala
+++ b/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/Daffodil.scala
@@ -46,6 +46,7 @@ import org.apache.daffodil.util.{ LoggingDefaults => SLoggingDefaults }
 import org.apache.daffodil.util.{ NullLogWriter => SNullLogWriter }
 import org.apache.daffodil.externalvars.{ Binding, ExternalVariablesLoader }
 import org.apache.daffodil.dsom.ExpressionCompilers
+import org.apache.daffodil.dsom.walker.RootView
 import org.apache.daffodil.compiler.{ InvalidParserException => SInvalidParserException }
 import org.apache.daffodil.processors.{ InvalidUsageException => SInvalidUsageException }
 import java.net.URI
@@ -338,6 +339,14 @@ class ProcessorFactory private[sapi] (private var pf: SProcessorFactory)
     new DataProcessor(dp)
   }
 
+  /**
+   * Exposes the RootView object corresponding to this ProcessorFactory.  This can
+   * be used to start a walk using the walkFromRoot method in a DSOM Walker.
+   */
+  object experimental {
+    val rootView: RootView = pf.rootView
+  }
+
 }
 
 /**