docs: def add_val(self, subj: Node, pred: URIRef, json_obj: JsonObj, json_key: str,
                  valuetype: Optional[URIRef] = None) -> Optional[BNode]:
          """
          Add the RDF representation of val to the graph as a target of subj, pred.  Note that FHIR lists are
          represented as a list of BNODE objects with a fhir:index discrimanant
          :param subj: graph subject
          :param pred: predicate
          :param json_obj: object containing json_key
          :param json_key: name of the value in the JSON resource
          :param valuetype: value type if NOT determinable by predicate
          :return: value node if target is a BNode else None
          """
          if json_key not in json_obj:
              print("Expecting to find object named '{}' in JSON:".format(json_key))
              print(json_obj._as_json_dumps())
              print("entry skipped")
              return None
          val = json_obj[json_key]
          if isinstance(val, List):
              list_idx = 0
              for lv in val:
                  entry_bnode = BNode()
                  # TODO: this is getting messy. Refactor and clean this up
                  if pred == FHIR.Bundle.entry:
                      entry_subj = URIRef(lv.fullUrl)
                      self.add(entry_bnode, FHIR.index, Literal(list_idx))
                      self.add_val(entry_bnode, FHIR.Bundle.entry.fullUrl, lv, 'fullUrl')
                      self.add(entry_bnode, FHIR.Bundle.entry.resource, entry_subj)
                      self.add(subj, pred, entry_bnode)
                      entry_mv = FHIRMetaVocEntry(self._vocabulary, FHIR.BundleEntryComponent)
                      for k, p in entry_mv.predicates().items():
                          if k not in ['resource', 'fullUrl'] and k in lv:
                              print("---> adding {}".format(k))
                              self.add_val(subj, p, lv, k)
                      FHIRResource(self._vocabulary, None,  self._base_uri, lv.resource, self._g,
                                   False, self._replace_narrative_text, False, resource_uri=entry_subj)
                  else:
                      self.add(entry_bnode, FHIR.index, Literal(list_idx))
                      if isinstance(lv, JsonObj):
                          self.add_value_node(entry_bnode, pred, lv, valuetype)
                      else:
                          vt = self._meta.predicate_type(pred)
                          atom_type = self._meta.primitive_datatype_nostring(vt) if vt else None
                          self.add(entry_bnode, FHIR.value, Literal(lv, datatype=atom_type))
                      self.add(subj, pred, entry_bnode)
                  list_idx += 1
          else:
              vt = self._meta.predicate_type(pred) if not valuetype else valuetype
              if self._meta.is_atom(pred):
                  if self._replace_narrative_text and pred == FHIR.Narrative.div and len(val) > 120:
                      val = REPLACED_NARRATIVE_TEXT
                  self.add(subj, pred, Literal(val))
              else:
                  v = BNode()
                  if self._meta.is_primitive(vt):
                      self.add(v, FHIR.value, Literal(str(val), datatype=self._meta.primitive_datatype_nostring(vt, val)))
                  else:
                      self.add_value_node(v, pred, val, valuetype)
                  self.add(subj, pred, v)
                  if pred == FHIR.Reference.reference:
                      self.add_reference(subj, val)
                  self.add_extension_val(v, json_obj, json_key)
                  return v
          return None