docs: Object getValue(
          MatchSpaceKey msg,
          Object contextValue)
          throws MatchingException, BadMessageFormatMatchingException
    {
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
        tc.entry(
          cclass,
          "getValue",
          "msg: " + msg + "contextValue: " + contextValue);
      
      // The value which we'll return    
      SetValEvaluationContext xpEval = null;    
  
      // May need to call MFP multiple times, if our context has multiple nodes
      if(contextValue != null)
      {
        // Currently this must be a list of nodes
        if (contextValue instanceof SetValEvaluationContext)
        {
          SetValEvaluationContext evalContext = (SetValEvaluationContext)contextValue;
  
          // Get the node list
          ArrayList wrappedParentList = evalContext.getWrappedNodeList();
          
          // If the list is empty, then we have yet to get the document root
          if(wrappedParentList.isEmpty())
          {
      	    //Set up a root (document) context for evaluation
            Object docRoot = Matching.getEvaluator().getDocumentRoot(msg);
              
            // Create an object to hold the wrapped node
            WrappedNodeResults wrapper = new WrappedNodeResults(docRoot);
            // Set the root into the evaluation context
            evalContext.addNode(wrapper);
          }
          
          // Iterate over the nodes
          Iterator iter = wrappedParentList.iterator();
  
          while(iter.hasNext())
          {
            WrappedNodeResults nextWrappedNode = (WrappedNodeResults)iter.next();       
            Object nextParentNode = nextWrappedNode.getNode();
            
            String debugString = "";
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
              tc.debug(this,cclass, "getValue", "Evaluation context node: " + nextWrappedNode);  
            
            // If no cached value we'll need to call MFP
            ArrayList stringList = nextWrappedNode.getEvalStringResult(id.getName());
              
            if(stringList == null)
            {
              // Call MFP to get the results for this node
              ArrayList childNodeList = 
                (ArrayList) msg.getIdentifierValue(id,
                                                   false,
                                                   nextParentNode, 
                                                   true); // true means return a nodelist
              
              // Process the retrieved nodes to get a list of Integers
              stringList = Matching.getEvaluator().castToStringList(childNodeList);
              
              // Add result to cache for next time
              nextWrappedNode.addEvalStringResult(id.getName(), stringList);
              
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                debugString = "Result from MFP ";
            }
            else
            {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                debugString = "Result from Cache ";
            }
            
            // Useful debug
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
            {
              String asString = ", type: String - <";
              if(stringList == null)
              {
                asString = asString + "null";
              }
              else
              {            
                Iterator iterDebug = stringList.iterator();
              
                boolean first = true;
                while(iterDebug.hasNext())
                {
                  String str = (String)iterDebug.next();
                  if(!first)
                    asString = asString + "," + str;
                  else
                  {
                    asString = asString + str;
                    first = false;
                  }
                }
              }
              asString = asString + ">"; 
              tc.debug(this,cclass, "getValue", debugString + "for identifier " + id.getName() + asString);
            } 
            
            // Build the return value as an XPathEvaluationContext
            if(xpEval == null)
              xpEval = new SetValEvaluationContext();
    
            // Add the wrapped node to the result
            xpEval.addNode(nextWrappedNode);
              
          } // eof while
        } // eof instanceof XPathEvaluationContext
      }
      
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
        tc.exit(this,cclass, "getValue", xpEval);
      return xpEval;
    }