///|
fn typed_element_is(element : Element, expected : TypeId) -> Bool {
  match element.value_type { Some(name) => schema_type(name).map(t => t.is_subtype_of(expected.name())).unwrap_or(false); None => false }
}

///|
fn typed_child_matches(element : Element, name : ExpandedName, substitution : Bool) -> Bool {
  if substitution { element.kind.substitutes(name) } else { element.kind.name() == name }
}

///|
fn[T] typed_single_child(element : Element, name : ExpandedName, substitution : Bool, project : (Element) -> Field[T]) -> Field[T] {
  let mut found : Field[T] = Absent
  let mut any=false
  for child in element.children {
    if !typed_child_matches(child,name,substitution) { continue }
    if any { return InvalidValue(Invalid(raw="duplicate child "+name.local_name,expected=name)) }
    found=project(child); any=true
  }
  found
}

///|
fn[T] typed_repeated_child(element : Element, name : ExpandedName, substitution : Bool, project : (Element) -> Field[T]) -> Field[ReadOnlyArray[T]] {
  let values : Array[T] = []
  for child in element.children {
    if !typed_child_matches(child,name,substitution) { continue }
    match project(child) { Present(value) => values.push(value); InvalidValue(value) => return InvalidValue(value); Absent => return InvalidValue(Invalid(raw=child.kind.local_name(),expected=name)) }
  }
  if values.is_empty() { Absent } else { Present(ReadOnlyArray::from_array(values)) }
}