stevedlawrence commented on code in PR #1112:
URL: https://github.com/apache/daffodil/pull/1112#discussion_r1387930288


##########
daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/SequenceTermRuntime1Mixin.scala:
##########
@@ -49,6 +50,10 @@ trait SequenceTermRuntime1Mixin { self: SequenceTermBase =>
       fillByteEv,
       maybeCheckByteAndBitOrderEv,
       maybeCheckBitOrderAndCharsetEv,
+      this match {
+        case sgr: SequenceGroupRef => sgr.isHidden
+        case _ => false
+      },

Review Comment:
   Is it worth adding an `isHidden` member to `SequenceTermBase` that defaults 
to false, and `SequenceGroupRef` overrides it? So this match case just becomes 
`isHidden`? Maybe that refactor is best done in another PR.



##########
daffodil-japi/src/main/scala/org/apache/daffodil/japi/Daffodil.scala:
##########
@@ -514,6 +508,13 @@ class DataProcessor private[japi] (private var dp: 
SDataProcessor)
    */
   def save(output: WritableByteChannel): Unit = dp.save(output)
 
+  /**
+   * Walks the handler over the runtime metadata structures
+   *
+   * @param handler - the handler is called-back during the walk as each 
metadata structure is encountered.
+   */
+  def walkMetadata(handler: MetadataHandler) = dp.walkMetadata(handler)

Review Comment:
   Can you add `: Unit` to this to make it obvious this doesn't return anything?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement

Review Comment:
   Do API users need access to the `parent`?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)

Review Comment:
   Have you looked at what is generated for JavaDoc to make sure it seems 
reasonable? I imagine this will all end up in the JAPI, it would be good to 
verify it looks sane.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement
+  def isNilled: Boolean
+  def isEmpty: Boolean
+  def asSimple: InfosetSimpleElement
+  def asComplex: InfosetComplexElement

Review Comment:
   What happens if a API user calls `asSimple` when the element is a complex, 
or vice versa? Do users even ever get a `InfosetElement`? Seems they should 
always get a `InfosetSimpleElement` or an `InfosetComplexElement` so these 
methods should be needed?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala:
##########
@@ -1558,6 +1590,29 @@ sealed class DISimple(override val erd: 
ElementRuntimeData)
     Assert.invariantFailed("Should not try to remove a child of a simple type")
   }
 
+  // call to getAnyRef here seems redundant
+  // but tests fail that compare objects if this call isn't here
+  // Boxing/Unboxing related perhaps
+  @inline private def v = dataValue.getAnyRef
+
+  override def getAnyRef: AnyRef = v.asInstanceOf[AnyRef]
+  override def getBigDecimal: JBigDecimal = v.asInstanceOf[JBigDecimal]
+  override def getCalendar: DFDLCalendar = v.asInstanceOf[DFDLCalendar]
+  override def getDate: DFDLDate = v.asInstanceOf[DFDLDate]
+  override def getTime: DFDLTime = v.asInstanceOf[DFDLTime]
+  override def getDateTime: DFDLDateTime = v.asInstanceOf[DFDLDateTime]
+  override def getByteArray: Array[Byte] = v.asInstanceOf[Array[Byte]]
+  override def getBoolean: JBoolean = v.asInstanceOf[JBoolean]
+  override def getNumber: JNumber = v.asInstanceOf[JNumber]
+  override def getByte: JByte = v.asInstanceOf[JByte]
+  override def getShort: JShort = v.asInstanceOf[JShort]
+  override def getInt: JInt = v.asInstanceOf[JInt]
+  override def getLong: JLong = v.asInstanceOf[JLong]
+  override def getDouble: JDouble = v.asInstanceOf[JDouble]
+  override def getFloat: JFloat = v.asInstanceOf[JFloat]
+  override def getBigInt: JBigInt = v.asInstanceOf[JBigInt]
+  override def getString: JString = v.asInstanceOf[JString]
+  override def getURI: URI = v.asInstanceOf[URI]

Review Comment:
   Can these just call `dataValue.getXYZ`? Doesn't that already do the 
asInstanceOf stuff? Avoids some duplication and makes it so if we ever chang 
DataValue this gets those changes?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/XMLInfosetOutputterMixin.scala:
##########
@@ -0,0 +1,62 @@
+/*
+ * 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.runtime1.infoset
+
+import org.apache.daffodil.lib.equality._
+import org.apache.daffodil.lib.util.Maybe
+import org.apache.daffodil.lib.xml.XMLUtils
+
+trait XMLInfosetOutputterMixin {
+
+  def remapped(dataValueAsString: String) =
+    XMLUtils.remapXMLIllegalCharactersToPUA(dataValueAsString)
+
+  /**
+   * String suitable for use in the text of a Processing Instruction.
+   *
+   * The text is a pseudo-XML string.
+   */
+  protected final def fmtInfo(diTerm: DITerm): Maybe[String] = {

Review Comment:
   Should we just drop the fmtInfo stuff? Seems like nothing uses it, and my 
guess it's is only used for debugging? If we do need access to fmtInfo, we 
should make that available in the CLI or VS Code debugger.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala:
##########
@@ -689,6 +698,10 @@ sealed class ElementRuntimeData(
       name
     }
   }
+
+  override def namespace: NS = dpathElementCompileInfo.namedQName.namespace
+  override def optNamespacePrefix: Option[String] = 
dpathElementCompileInfo.namedQName.prefix
+  override def sscd: String = dpathElementCompileInfo.sscd

Review Comment:
   I've forgotten what does sscd stands for. Which makes me thinks it's used 
rarely enough that maybe it needs a more descriptive name? Could be done in 
another PR, since it's not related to this.



##########
daffodil-japi/src/main/scala/org/apache/daffodil/japi/infoset/Infoset.scala:
##########
@@ -161,7 +160,7 @@ abstract class InfosetOutputter extends SInfosetOutputter {
    */
 
   @throws[Exception]
-  def startSimple(diSimple: DISimple): Unit
+  def startSimple(diSimple: InfosetSimpleElement): Unit

Review Comment:
   We should rename the parameter names too, probably just drop the `di`, e.g. 
`diSimple` -> `simple`.



##########
daffodil-lib/src/main/scala/org/apache/daffodil/lib/xml/QNameBase.scala:
##########
@@ -350,6 +349,27 @@ trait QNameBase extends Serializable {
     if (prefix.isDefined) prefix.get + ":" + local else local
   }
 
+  private lazy val _Prefix_LocalName = toQNameString.replace(":", "_")
+
+  /**
+   * Maps the QName to a name like prefix_localName for use with
+   * data models/representations that don't have namespaces.
+   */
+  def toPrefix_localName = {

Review Comment:
   I'm not sure I love this name. I feel like this wants to be `toSafeString` 
or something like that. `safe` is probably the wrong word, but `toFooString` 
feels like a more clear name about what it's doing.



##########
daffodil-lib/src/main/scala/org/apache/daffodil/lib/xml/QNameBase.scala:
##########
@@ -350,6 +349,27 @@ trait QNameBase extends Serializable {
     if (prefix.isDefined) prefix.get + ":" + local else local
   }
 
+  private lazy val _Prefix_LocalName = toQNameString.replace(":", "_")

Review Comment:
   This logic feels like it wants to be in the MetaDataHandler or 
InfosetWalkers. Different implementations are possibly going to have different 
restrictions on what makes a valid name or a name that fits best into their 
system. I also imagine most implementations could get away with just dropping 
the namespace altogether. Schemas that rely on namespaces for uniqueness are 
fairly rare, and those that do exist should probably be changed or deprecated.



##########
daffodil-japi/src/main/scala/org/apache/daffodil/japi/Daffodil.scala:
##########
@@ -514,6 +508,13 @@ class DataProcessor private[japi] (private var dp: 
SDataProcessor)
    */
   def save(output: WritableByteChannel): Unit = dp.save(output)
 
+  /**
+   * Walks the handler over the runtime metadata structures
+   *
+   * @param handler - the handler is called-back during the walk as each 
metadata structure is encountered.
+   */
+  def walkMetadata(handler: MetadataHandler) = dp.walkMetadata(handler)

Review Comment:
   I'm not sure I love the name `walkMetadata`. If you're not familiar with 
Daffodil internals, I'm not sure you would know what "metadata" means and if 
you would want to walk it. That said, I can't think of a better name, so maybe 
it just needs a comment explaining what what it means to walk metadata.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement
+  def isNilled: Boolean
+  def isEmpty: Boolean

Review Comment:
   What does `isEmpty` represent? Seems an API user should never be handed an 
infoset element that is empty.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement
+  def isNilled: Boolean
+  def isEmpty: Boolean
+  def asSimple: InfosetSimpleElement
+  def asComplex: InfosetComplexElement
+
+  /*
+   * For API users to avoid the need to access RuntimeData
+   */
+  def metadata: ElementMetadata
+  def name = metadata.name
+  def namespace = metadata.namespace

Review Comment:
   Thoughts on dropping name and namespace since users have access to the 
metadata?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Metadata.scala:
##########
@@ -0,0 +1,80 @@
+package org.apache.daffodil.runtime1.api
+
+import org.apache.daffodil.lib.exceptions.SchemaFileLocation
+import org.apache.daffodil.lib.xml.NS
+import org.apache.daffodil.lib.xml.NamedQName
+import org.apache.daffodil.runtime1.dpath.PrimTypeNode
+
+/*
+ * This is the supportable API for access to the RuntimeData structures
+ */
+trait Metadata {
+  def schemaFileLocation: SchemaFileLocation

Review Comment:
   `SchemaFileLocation` isn't part of the api. In the JAPI/SAPI we map things 
to a `LocationInSchemaFile` (not sure if that's the same thing?). I'm not sure 
how this would show up in the JavaDocs



##########
daffodil-lib/src/main/scala/org/apache/daffodil/lib/xml/QNameBase.scala:
##########
@@ -350,6 +349,27 @@ trait QNameBase extends Serializable {
     if (prefix.isDefined) prefix.get + ":" + local else local
   }
 
+  private lazy val _Prefix_LocalName = toQNameString.replace(":", "_")

Review Comment:
   Can this just be something like `prefix + "_" + localName`?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala:
##########
@@ -1650,32 +1708,71 @@ sealed class DIComplex(override val erd: 
ElementRuntimeData)
     }
   }
 
+  final def getChild(
+    childMetadata: ElementMetadata,
+    enableLinearSearch: Boolean,

Review Comment:
   I suggest this goes away. Users should only get access to children via a 
walker. If they need by-name access, then they need to walk the infoset and 
build their own internal representation that gives them that.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement
+  def isNilled: Boolean
+  def isEmpty: Boolean
+  def asSimple: InfosetSimpleElement
+  def asComplex: InfosetComplexElement
+
+  /*
+   * For API users to avoid the need to access RuntimeData
+   */
+  def metadata: ElementMetadata
+  def name = metadata.name
+  def namespace = metadata.namespace
+}
+
+trait InfosetComplexElement extends InfosetElement {
+  override def metadata: ComplexElementMetadata
+  def getChildElement(childMetadata: ElementMetadata): InfosetElement
+  def getChildArray(childMetadata: ElementMetadata): InfosetArray
+  def getChild(childMetadata: ElementMetadata): InfosetItem
+}
+
+trait InfosetSimpleElement extends InfosetElement {
+
+  override def metadata: SimpleElementMetadata
+
+  /**
+   * Caches the string so we're not allocating strings repeatedly
+   */
+  def dataValueAsString: String
+
+  /*
+   * These are so that API users don't have to know about our
+   * very Scala-oriented DataValue type system.
+   */
+  def getAnyRef: AnyRef

Review Comment:
   Should we remove `getAnyRef`? A API user should never need that. 



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement
+  def isNilled: Boolean
+  def isEmpty: Boolean
+  def asSimple: InfosetSimpleElement
+  def asComplex: InfosetComplexElement
+
+  /*
+   * For API users to avoid the need to access RuntimeData
+   */
+  def metadata: ElementMetadata
+  def name = metadata.name
+  def namespace = metadata.namespace
+}
+
+trait InfosetComplexElement extends InfosetElement {
+  override def metadata: ComplexElementMetadata
+  def getChildElement(childMetadata: ElementMetadata): InfosetElement
+  def getChildArray(childMetadata: ElementMetadata): InfosetArray
+  def getChild(childMetadata: ElementMetadata): InfosetItem
+}
+
+trait InfosetSimpleElement extends InfosetElement {
+
+  override def metadata: SimpleElementMetadata
+
+  /**
+   * Caches the string so we're not allocating strings repeatedly
+   */
+  def dataValueAsString: String
+
+  /*
+   * These are so that API users don't have to know about our
+   * very Scala-oriented DataValue type system.
+   */
+  def getAnyRef: AnyRef
+  def getBigDecimal: JBigDecimal
+  def getCalendar: DFDLCalendar
+  def getDate: DFDLDate
+  def getTime: DFDLTime
+  def getDateTime: DFDLDateTime
+  def getByteArray: Array[Byte]
+  def getBoolean: JBoolean
+  def getNumber: JNumber
+  def getByte: JByte
+  def getShort: JShort
+  def getInt: JInt
+  def getLong: JLong
+  def getDouble: JDouble
+  def getFloat: JFloat
+  def getBigInt: JBigInt
+  def getString: JString
+  def getURI: URI
+}

Review Comment:
   We probably need javadocs on these functions individually. It's going to be 
repetetive, but is needed for Javadocs to look correct.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement
+  def isNilled: Boolean
+  def isEmpty: Boolean
+  def asSimple: InfosetSimpleElement
+  def asComplex: InfosetComplexElement
+
+  /*
+   * For API users to avoid the need to access RuntimeData
+   */
+  def metadata: ElementMetadata
+  def name = metadata.name
+  def namespace = metadata.namespace
+}
+
+trait InfosetComplexElement extends InfosetElement {
+  override def metadata: ComplexElementMetadata
+  def getChildElement(childMetadata: ElementMetadata): InfosetElement
+  def getChildArray(childMetadata: ElementMetadata): InfosetArray
+  def getChild(childMetadata: ElementMetadata): InfosetItem
+}
+
+trait InfosetSimpleElement extends InfosetElement {
+
+  override def metadata: SimpleElementMetadata
+
+  /**
+   * Caches the string so we're not allocating strings repeatedly
+   */
+  def dataValueAsString: String
+
+  /*
+   * These are so that API users don't have to know about our
+   * very Scala-oriented DataValue type system.
+   */
+  def getAnyRef: AnyRef
+  def getBigDecimal: JBigDecimal
+  def getCalendar: DFDLCalendar
+  def getDate: DFDLDate
+  def getTime: DFDLTime
+  def getDateTime: DFDLDateTime
+  def getByteArray: Array[Byte]
+  def getBoolean: JBoolean
+  def getNumber: JNumber
+  def getByte: JByte
+  def getShort: JShort
+  def getInt: JInt
+  def getLong: JLong
+  def getDouble: JDouble
+  def getFloat: JFloat
+  def getBigInt: JBigInt
+  def getString: JString
+  def getURI: URI
+}
+
+trait InfosetDocument extends InfosetItem {
+  override def metadata: ElementMetadata
+}
+
+trait InfosetItem {
+
+  def metadata: Metadata
+
+  /**
+   * The totalElementCount is the total count of how many elements this 
InfosetItem contains.
+   *
+   * (Used to call this 'size', but size is often a length-like thing, so 
changed name
+   * to be more distinctive)
+   */
+  def totalElementCount: Long

Review Comment:
   Do API users need this? I'm not even sure what this value represents or what 
it's used for. Looking at the implementation, totalElementCount is the number 
of children recursively? Seems like that number wouldn't be all that useful. 
And it might not even be accurate, since I imagine it's possible all the 
children haven't been finalized yet, since the infoset is often in a state 
where parts can be walked but parts can't.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement
+  def isNilled: Boolean
+  def isEmpty: Boolean
+  def asSimple: InfosetSimpleElement
+  def asComplex: InfosetComplexElement
+
+  /*
+   * For API users to avoid the need to access RuntimeData
+   */
+  def metadata: ElementMetadata
+  def name = metadata.name
+  def namespace = metadata.namespace
+}
+
+trait InfosetComplexElement extends InfosetElement {
+  override def metadata: ComplexElementMetadata
+  def getChildElement(childMetadata: ElementMetadata): InfosetElement
+  def getChildArray(childMetadata: ElementMetadata): InfosetArray
+  def getChild(childMetadata: ElementMetadata): InfosetItem
+}

Review Comment:
   Should we grant access to children this way? This allows users to walk and 
infoset themselves, which is dangerous. An infoset is often in a state where it 
is only partially built and children should not be accessed, which only 
Daffodil internals know when that is.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Metadata.scala:
##########
@@ -0,0 +1,80 @@
+package org.apache.daffodil.runtime1.api
+
+import org.apache.daffodil.lib.exceptions.SchemaFileLocation
+import org.apache.daffodil.lib.xml.NS
+import org.apache.daffodil.lib.xml.NamedQName
+import org.apache.daffodil.runtime1.dpath.PrimTypeNode
+
+/*
+ * This is the supportable API for access to the RuntimeData structures
+ */
+trait Metadata {
+  def schemaFileLocation: SchemaFileLocation
+  def path: String
+  def diagnosticDebugName: String
+  override def toString = diagnosticDebugName
+}
+
+trait TermMetadata extends Metadata {
+  def isArray: Boolean
+}
+
+trait ElementMetadata extends TermMetadata {
+  def isSimpleType: Boolean
+  def isComplexType: Boolean
+
+  def name: String
+  def namespace: NS
+  def optNamespacePrefix: Option[String]
+  def isArray: Boolean
+  def isOptional: Boolean
+  def namedQName: NamedQName
+
+  def sscd: String
+  def isNillable: Boolean
+
+  def runtimeProperties: java.util.Map[String, String]
+
+}
+
+trait ComplexElementMetadata extends ElementMetadata {
+
+  def childMetadata: Seq[ElementMetadata]

Review Comment:
   Similar questions as earlier, should we grant access to children stuff? That 
would allow users to implement their own walkers, which feels unsafe. Seems we 
only want to give access to this element and only this element. They'll see the 
childMetadata when we walk to it.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import org.apache.daffodil.lib.calendar.DFDLCalendar
+import org.apache.daffodil.lib.calendar.DFDLDate
+import org.apache.daffodil.lib.calendar.DFDLDateTime
+import org.apache.daffodil.lib.calendar.DFDLTime
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+  override def metadata: ElementMetadata // the element that is an array
+  def getOccurrence(occursIndex: Long): InfosetElement
+  def length: Long
+  final def apply(occursIndex: Long): InfosetElement = 
getOccurrence(occursIndex)
+  final def apply(occursIndex: Int) : InfosetElement = 
getOccurrence(occursIndex.toLong)
+}
+
+/**
+ * API access to elements of the DFDL Infoset
+ */
+trait InfosetElement extends InfosetItem {
+  def parent: InfosetComplexElement
+  def isNilled: Boolean
+  def isEmpty: Boolean
+  def asSimple: InfosetSimpleElement
+  def asComplex: InfosetComplexElement
+
+  /*
+   * For API users to avoid the need to access RuntimeData
+   */
+  def metadata: ElementMetadata
+  def name = metadata.name
+  def namespace = metadata.namespace
+}
+
+trait InfosetComplexElement extends InfosetElement {
+  override def metadata: ComplexElementMetadata
+  def getChildElement(childMetadata: ElementMetadata): InfosetElement
+  def getChildArray(childMetadata: ElementMetadata): InfosetArray
+  def getChild(childMetadata: ElementMetadata): InfosetItem
+}
+
+trait InfosetSimpleElement extends InfosetElement {
+
+  override def metadata: SimpleElementMetadata
+
+  /**
+   * Caches the string so we're not allocating strings repeatedly
+   */
+  def dataValueAsString: String
+
+  /*
+   * These are so that API users don't have to know about our
+   * very Scala-oriented DataValue type system.
+   */
+  def getAnyRef: AnyRef
+  def getBigDecimal: JBigDecimal
+  def getCalendar: DFDLCalendar
+  def getDate: DFDLDate
+  def getTime: DFDLTime
+  def getDateTime: DFDLDateTime

Review Comment:
   These calendar/time types are kindof internal I think? We might want to 
think if there's something better to return here, like a `Calendar` or some 
other Java date/time structure.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala:
##########
@@ -1157,6 +1180,8 @@ final class DIArray(
 ) extends DINode
   with InfosetArray {
 
+  override def metadata: ElementMetadata = erd.asInstanceOf[ElementMetadata]

Review Comment:
   Is `asInstanceOf` needed here? If `erd` implements `ElementMetaData`, should 
it be fine to just return erd?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala:
##########
@@ -1079,27 +1101,27 @@ sealed trait DIElement
   protected final var _isHidden = false
   final def isHidden: Boolean = _isHidden
 
-  override def setHidden(): Unit = {
+  def setHidden(): Unit = {
     _isHidden = true
   }
 
   final def runtimeData = erd
-  protected final var _parent: InfosetComplexElement = null
+  protected final var _parent: DIComplex = null

Review Comment:
   This is a great change and something we should do everywhere infosets appear 
in the code (maybe this PR does that?). Seems Daffodil wants use the `DI` 
variant internally everywhere. The only place the non-`DI` variant should is 
the public functions like the walkers so we can limit what parts a user has 
acess to. But Daffodil internals should have access to all parts of a DI. I 
feel like there are a number of places where that's not the case (though maybe 
this PR fixed all those?) and should make a lot of `asInstanceOf[DIFoo]` go 
away.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Metadata.scala:
##########
@@ -0,0 +1,80 @@
+package org.apache.daffodil.runtime1.api
+
+import org.apache.daffodil.lib.exceptions.SchemaFileLocation
+import org.apache.daffodil.lib.xml.NS
+import org.apache.daffodil.lib.xml.NamedQName
+import org.apache.daffodil.runtime1.dpath.PrimTypeNode
+
+/*
+ * This is the supportable API for access to the RuntimeData structures
+ */
+trait Metadata {
+  def schemaFileLocation: SchemaFileLocation
+  def path: String
+  def diagnosticDebugName: String
+  override def toString = diagnosticDebugName
+}
+
+trait TermMetadata extends Metadata {
+  def isArray: Boolean
+}
+
+trait ElementMetadata extends TermMetadata {
+  def isSimpleType: Boolean
+  def isComplexType: Boolean
+
+  def name: String
+  def namespace: NS
+  def optNamespacePrefix: Option[String]
+  def isArray: Boolean
+  def isOptional: Boolean
+  def namedQName: NamedQName
+
+  def sscd: String

Review Comment:
   Need a new name for sscd if this is going to be publicly available to users.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/ScalaXMLInfosetOutputter.scala:
##########
@@ -17,20 +17,23 @@
 
 package org.apache.daffodil.runtime1.infoset
 
-import scala.collection.mutable.ListBuffer
-import scala.xml.MetaData
-import scala.xml.Null
-import scala.xml.UnprefixedAttribute
-
 import org.apache.daffodil.lib.exceptions.Assert
 import org.apache.daffodil.lib.util.MStackOf
 import org.apache.daffodil.lib.util.Maybe
 import org.apache.daffodil.lib.xml.XMLUtils
+import org.apache.daffodil.runtime1.api.InfosetArray
+import org.apache.daffodil.runtime1.api.InfosetComplexElement
+import org.apache.daffodil.runtime1.api.InfosetSimpleElement
 import org.apache.daffodil.runtime1.dpath.NodeInfo
 
+import scala.collection.mutable.ListBuffer
+import scala.xml.MetaData
+import scala.xml.Null
+import scala.xml.UnprefixedAttribute

Review Comment:
   You might need to change your IDE settings. I think scala imports are 
supposed to be before daffodil imports. Can you configure your IDE to use the 
.scalafmt.conf file?



##########
daffodil-japi/src/main/scala/org/apache/daffodil/japi/Daffodil.scala:
##########
@@ -514,6 +508,13 @@ class DataProcessor private[japi] (private var dp: 
SDataProcessor)
    */
   def save(output: WritableByteChannel): Unit = dp.save(output)
 
+  /**
+   * Walks the handler over the runtime metadata structures
+   *
+   * @param handler - the handler is called-back during the walk as each 
metadata structure is encountered.
+   */
+  def walkMetadata(handler: MetadataHandler) = dp.walkMetadata(handler)

Review Comment:
   Very good points. Suggest these be added to a comment somewhere.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/JDOMInfosetOutputter.scala:
##########
@@ -46,7 +49,8 @@ class JDOMInfosetOutputter extends InfosetOutputter with 
XMLInfosetOutputter {
     result = Maybe(root.asInstanceOf[org.jdom2.Document])
   }
 
-  def startSimple(diSimple: DISimple): Unit = {
+  override def startSimple(se: InfosetSimpleElement): Unit = {
+    val diSimple = se.asInstanceOf[DISimple]

Review Comment:
   Is casting to a DISimple done to avoid having to update other outputters and 
deal with that later? I assume the goal is these infoset outputters should only 
use InfosetFooEelements? Doing the conversion would be good evidence that the 
InfosetElement API interface makes everything needed available.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/MetadataWalker.scala:
##########
@@ -0,0 +1,76 @@
+package org.apache.daffodil.runtime1.processors
+
+import org.apache.daffodil.lib.exceptions.Assert
+import org.apache.daffodil.runtime1.api.MetadataHandler
+import org.apache.daffodil.runtime1.api.SequenceMetadata
+
+/**
+ * Walks the schema, but not the DSOM schema, it walks the RuntimeData objects 
that
+ * represent the DFDL schema at runtime.
+ *
+ * @param dp
+ */
+class MetadataWalker(private val dp: DataProcessor) {
+
+  private lazy val rootERD = dp.ssrd.elementRuntimeData
+
+  def walk(handler: MetadataHandler): Unit = {
+    walkTerm(handler, rootERD)
+  }
+
+  private def walkTerm(handler: MetadataHandler, trd: TermRuntimeData): Unit = 
{
+    trd match {
+      case err: ErrorERD => Assert.invariantFailed("should not get ErrorERDs")
+      case erd: ElementRuntimeData => walkElement(handler, erd)
+      case srd: SequenceRuntimeData => walkSequence(handler, srd)
+      case crd: ChoiceRuntimeData => walkChoice(handler, crd)
+      case _ => Assert.invariantFailed(s"unrecognized TermRuntimeData subtype: 
$trd")
+    }
+  }
+
+  private def walkElement(handler: MetadataHandler, erd: ElementRuntimeData): 
Unit = {
+    if (erd.optComplexTypeModelGroupRuntimeData.isDefined)
+      walkComplexElement(handler, erd)
+    else
+      walkSimpleElement(handler, erd)
+  }
+
+  private def walkComplexElement(
+    handler: MetadataHandler,
+    erd: ElementRuntimeData,
+  ): Unit = {
+    val mgrd = erd.optComplexTypeModelGroupRuntimeData.getOrElse {
+      Assert.invariantFailed("not a complex type element")
+    }
+    handler.startComplexElementMetadata(erd)
+    walkTerm(handler, mgrd)
+    handler.endComplexElementMetadata(erd)
+  }
+
+  private def walkSimpleElement(
+    handler: MetadataHandler,
+    erd: ElementRuntimeData,
+  ): Unit = {
+    handler.simpleElementMetadata(erd)
+  }
+
+  private def walkSequence(handler: MetadataHandler, sm: SequenceMetadata): 
Unit = {
+    val srd = sm.asInstanceOf[SequenceRuntimeData]
+    if (!srd.isHidden) {
+      // handler.startSequence()
+      srd.groupMembers.map { trd =>
+        walkTerm(handler, trd)
+      }
+      // handler.endSequence()
+    }
+  }
+
+  private def walkChoice(handler: MetadataHandler, crd: ChoiceRuntimeData): 
Unit = {
+    // handler.startChoice()

Review Comment:
   Seems a walker handler would want to know that the children are options of a 
choice and could be converted to a union or something. Can they know that 
without start/endChoice?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to