/// <summary> Navigates to a specific location in the message</summary> private void drillHere(IStructure destination) { IStructure pathElem = destination; ArrayList pathStack = new ArrayList(); ArrayList indexStack = new ArrayList(); do { MessageIterator.Index index = MessageIterator.getIndex(pathElem.ParentStructure, pathElem); indexStack.Add(index); pathElem = pathElem.ParentStructure; pathStack.Add(pathElem); } while (!root.Equals(pathElem) && !typeof(IMessage).IsAssignableFrom(pathElem.GetType())); if (!root.Equals(pathElem)) { throw new HL7Exception("The destination provided is not under the root of this navigator"); } reset(); while (!(pathStack.Count == 0)) { IGroup parent = (IGroup)SupportClass.StackSupport.Pop(pathStack); MessageIterator.Index index = (MessageIterator.Index)SupportClass.StackSupport.Pop(indexStack); int child = search(parent.Names, index.name); if (!(pathStack.Count == 0)) { drillDown(child, 0); } else { toChild(child); } } }
/* for configurability (maybe to add later, replacing hard-coded options * in nextFromEndOfGroup) ... * public void setSearchLevel(String level) { * if (WHOLE_GROUP.equals(level)) { * this.findUpToFirstRequired = false; * this.findFirstDescendentsOnly = false; * } else if (FIRST_DESCENDENTS_ONLY.equals(level)) { * this.findUpToFirstRequired = false; * this.findFirstDescendentsOnly = true; * } else if (UP_TO_FIRST_REQUIRED.equals(level)) { * this.findUpToFirstRequired = true; * this.findFirstDescendentsOnly = false; * } else { * throw IllegalArgumentException(level + " is not a valid search level. Should be WHOLE_GROUP, etc."); * } * } * * public String getSearchLevel() { * String level = WHOLE_GROUP; * if (this.findFirstDescendentsOnly) { * level = FIRST_DESCENDENTS_ONLY; * } else if (this.findUpTpFirstRequired) { * level = UP_TO_FIRST_REQUIRED; * } * return level; * }*/ #region Public Methods and Operators /// <summary> /// Determines whether the given structure matches the given name, or contains a child that does. /// </summary> /// /// <exception cref="ApplicationException"> Thrown when an Application error condition occurs. </exception> /// /// <param name="s"> the structure to check. </param> /// <param name="name"> the name to look for. </param> /// <param name="firstDescendentsOnly"> only checks first descendents (i.e. first child, first /// child of first child, etc.) In theory the first child of /// a group should always be present, and we don't use this /// method with subsequent children because finding the next /// position within a group is straightforward. </param> /// <param name="upToFirstRequired"> only checks first descendents and of their siblings up to /// the first required one. This may be needed because in /// practice some first children of groups are not required. </param> /// /// <returns> true if the object is in this collection, false if not. </returns> public static bool contains(IStructure s, System.String name, bool firstDescendentsOnly, bool upToFirstRequired) { bool contains = false; if (typeof(ISegment).IsAssignableFrom(s.GetType())) { if (s.GetStructureName().Equals(name)) { contains = true; } } else { IGroup g = (IGroup)s; System.String[] names = g.Names; for (int i = 0; i < names.Length && !contains; i++) { try { contains = MessageIterator.contains( g.GetStructure(names[i], 0), name, firstDescendentsOnly, upToFirstRequired); if (firstDescendentsOnly) { break; } if (upToFirstRequired && g.IsRequired(names[i])) { break; } } catch (HL7Exception e) { throw new System.ApplicationException("HL7Exception due to bad index: " + e.Message); } } } return(contains); }
/// <summary> Iterates through the message tree to the next segment/group location (regardless /// of whether an instance of the segment exists). If the end of the tree is /// reached, starts over at the root. Only enters the first repetition of a /// repeating group -- explicit navigation (using the drill...() methods) is /// necessary to get to subsequent reps. /// </summary> /// <param name="segmentsOnly">if true, only stops at segments (not groups). /// </param> /// <param name="loop">if true, loops back to beginning when end of msg reached; if false, /// throws HL7Exception if end of msg reached. /// </param> public virtual void Iterate(bool segmentsOnly, bool loop) { IStructure start = null; if (currentChild == -1) { start = CurrentGroup; } else { start = CurrentGroup.GetStructure(childNames[currentChild]); } // using a non-existent direction and not allowing segment creation means that only // the first rep of anything is traversed. IEnumerator it = new MessageIterator(start, "doesn't exist", false); if (segmentsOnly) { FilterIterator.IPredicate predicate = new AnonymousClassPredicate(this); it = new FilterIterator(it, predicate); } if (it.MoveNext()) { var next = (IStructure)it.Current; DrillHere(next); } else if (loop) { Reset(); } else { throw new HL7Exception( "End of message reached while iterating without loop", ErrorCode.APPLICATION_INTERNAL_ERROR); } }
/// <summary> Parses a message string and returns the corresponding Message /// object. Unexpected segments added at the end of their group. /// /// </summary> /// <throws> HL7Exception if the message is not correctly formatted. </throws> /// <throws> EncodingNotSupportedException if the message encoded </throws> /// <summary> is not supported by this parser. /// </summary> protected internal override IMessage DoParse(String message, String version) { //try to instantiate a message object of the right class MessageStructure structure = GetStructure(message); IMessage m = InstantiateMessage(structure.messageStructure, version, structure.explicitlyDefined); //MessagePointer ptr = new MessagePointer(this, m, getEncodingChars(message)); MessageIterator messageIter = new MessageIterator(m, "MSH", true); FilterIterator.IPredicate segmentsOnly = new AnonymousClassPredicate(this); FilterIterator segmentIter = new FilterIterator(messageIter, segmentsOnly); String[] segments = Split(message, segDelim); EncodingCharacters encodingChars = GetEncodingChars(message); for (int i = 0; i < segments.Length; i++) { //get rid of any leading whitespace characters ... if (segments[i] != null && segments[i].Length > 0 && Char.IsWhiteSpace(segments[i][0])) segments[i] = StripLeadingWhitespace(segments[i]); //sometimes people put extra segment delimiters at end of msg ... if (segments[i] != null && segments[i].Length >= 3) { String name = segments[i].Substring(0, (3) - (0)); log.Debug("Parsing segment " + name); messageIter.Direction = name; FilterIterator.IPredicate byDirection = new AnonymousClassPredicate1(name, this); FilterIterator dirIter = new FilterIterator(segmentIter, byDirection); if (dirIter.MoveNext()) { Parse((ISegment) dirIter.Current, segments[i], encodingChars); } } } return m; }
/// <summary> Parses a message string and returns the corresponding Message /// object. Unexpected segments added at the end of their group. /// /// </summary> /// <throws> HL7Exception if the message is not correctly formatted. </throws> /// <throws> EncodingNotSupportedException if the message encoded </throws> /// <summary> is not supported by this parser. /// </summary> protected internal override IMessage DoParse(String message, String version) { //try to instantiate a message object of the right class MessageStructure structure = GetStructure(message); IMessage m = InstantiateMessage(structure.messageStructure, version, structure.explicitlyDefined); //MessagePointer ptr = new MessagePointer(this, m, getEncodingChars(message)); MessageIterator messageIter = new MessageIterator(m, "MSH", true); FilterIterator.IPredicate segmentsOnly = new AnonymousClassPredicate(this); FilterIterator segmentIter = new FilterIterator(messageIter, segmentsOnly); string lastSegmentName = null; String[] segments = Split(message, segDelim); EncodingCharacters encodingChars = GetEncodingChars(message); for (int i = 0; i < segments.Length; i++) { //get rid of any leading whitespace characters ... if (segments[i] != null && segments[i].Length > 0 && Char.IsWhiteSpace(segments[i][0])) segments[i] = StripLeadingWhitespace(segments[i]); //sometimes people put extra segment delimiters at end of msg ... if (segments[i] != null && segments[i].Length >= 3) { String name = segments[i].Substring(0, (3) - (0)); log.Debug("Parsing segment " + name); if (!name.Equals(lastSegmentName, StringComparison.CurrentCultureIgnoreCase)) { // If the message iterator passes a segment that is later encountered the message object won't be properly parsed. // Rebuild the iterator for each segment, or fix iterator logic in handling unexpected segments. messageIter = new MessageIterator(m, "MSH", true); segmentsOnly = new AnonymousClassPredicate(this); segmentIter = new FilterIterator(messageIter, segmentsOnly); lastSegmentName = name; } messageIter.Direction = name; FilterIterator.IPredicate byDirection = new AnonymousClassPredicate1(name, this); FilterIterator dirIter = new FilterIterator(segmentIter, byDirection); if (dirIter.MoveNext()) { Parse((ISegment) dirIter.Current, segments[i], encodingChars); } } } return m; }
/// <summary> Iterates through the message tree to the next segment/group location (regardless /// of whether an instance of the segment exists). If the end of the tree is /// reached, starts over at the root. Only enters the first repetition of a /// repeating group -- explicit navigation (using the drill...() methods) is /// necessary to get to subsequent reps. /// </summary> /// <param name="segmentsOnly">if true, only stops at segments (not groups) /// </param> /// <param name="loop">if true, loops back to beginning when end of msg reached; if false, /// throws HL7Exception if end of msg reached /// </param> public virtual void iterate(bool segmentsOnly, bool loop) { IStructure start = null; if (this.currentChild == -1) { start = this.currentGroup; } else { start = (this.currentGroup.GetStructure(this.childNames[this.currentChild])); } //using a non-existent direction and not allowing segment creation means that only //the first rep of anything is traversed. System.Collections.IEnumerator it = new MessageIterator(start, "doesn't exist", false); if (segmentsOnly) { FilterIterator.IPredicate predicate = new AnonymousClassPredicate(this); it = new FilterIterator(it, predicate); } if (it.MoveNext()) { IStructure next = (IStructure)it.Current; drillHere(next); } else if (loop) { this.reset(); } else { throw new HL7Exception("End of message reached while iterating without loop", HL7Exception.APPLICATION_INTERNAL_ERROR); } }