[MOBY-guts] biomoby commit

Mark Wilkinson mwilkinson at pub.open-bio.org
Wed Apr 14 19:56:59 UTC 2004


mwilkinson
Wed Apr 14 15:56:59 EDT 2004
Update of /home/repository/moby/moby-live/Perl/MOBY
In directory pub.open-bio.org:/tmp/cvs-serv13353/Perl/MOBY

Modified Files:
	CommonSubs.pm 
Log Message:
CommonSubs now includes support for services that use Secondary Parameter's.  I am also almost finished writing an OO-interface for building/deconstructing MOBY objects, so that people don't have to learn the XML::DOM API. This is incomplete and untested yet, so don't shoot me if it doesn't work.  See the docs for CommonSubs 'complexServiceInputParser' for details on how to manage services that use multiple inputs and/or secondary parameters.  As soon as I get this OO interface working I will create an equivalent subroutine that parses the input into objects (but I wont remove this routine, so it wont break you servies if you use it)

moby-live/Perl/MOBY CommonSubs.pm,1.43,1.44
===================================================================
RCS file: /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.pm,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -r1.43 -r1.44
--- /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.pm	2004/03/19 00:24:10	1.43
+++ /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.pm	2004/04/14 19:56:59	1.44
@@ -16,51 +16,49 @@
 =head2 Service-Side Paradigm
 
 The following is a generalized architecture for *all*
-BioMOBY services showing how to parse incoming messages...
+BioMOBY services showing how to parse incoming messages
+using the subroutines provided in CommonSubs
 
  sub myServiceName {
-   my ($caller, $message) = @_;  # get the incoming MOBY query XML
-
-   my @queries = getInputs($message);  # returns XML::DOM nodes
-   my $MOBY_RESPONSE = "";           # set empty response
- 
-   foreach my $query(@queries){
-
-     my $queryID = getInputID($query);  # get the queryID attribute of the queryInput
-     
-     my @input_articles = getArticles($query); # get the Simple/Collection articles making up this query
-     foreach my $input(@input_articles){       # input is a listref
-
-        my ($articleName, $article) = @{$input}; # get the named article
-        
-        my $simple = isSimpleArticle($article);  # articles may be simple or collection
-        my $collection = isCollectionArticle($article);
-
-        if ($collection){
-
-            # do something wtih the collection...
-            # for example...
-            my @simples = getCollectedSimples($article);
-            # blah blah blah...
-            
-        } elsif ($simple){
-            # maybe you just need the ID of the incoming query:
-            my ($id) = getSimpleArticleIDs('NCBI_gi', $article); # if you need the ID
-
-            # or maybe you are going to do something with the content?
-            # for example, this will get the array of text lines
-            # for the moby:String object with the articleName 'SequenceString'
-            # that is in this $article
-            my @sequence = getNodeContentWithArticle($article, "String", "SequenceString");
-
-            #  DO YOUR ANALYSIS HERE
-            my $result = ""; #whatever you analysis says
-            
-            $MOBY_RESPONSE .= simpleResponse($result, "outputArticlename", $queryID);
+    my ($caller, $data) = @_;
+    my $MOBY_RESPONSE; # holds the response raw XML
+    
+        # genericServiceInputParser
+        # unpacks incoming message into an array of arrarefs.
+        # Each element of the array is a queryInput block, or a mobyData block
+        # the arrayref has the following structure:
+        # [SIMPLE, $queryID, $simple]
+        # the first element is a constant "SIMPLE" or "COLLECTION"
+        # the second element is the queryID (required for enumerating the responses)
+        # the third element is the XML::DOM for the Simple or Collection block    
+    my (@inputs)= genericServiceInputParser($data); 
+        # or fail properly with an empty response
+    return SOAP::Data->type('base64' => responseHeader("my.authURI.com") . responseFooter()) unless (scalar(@inputs));
+    
+        # you only need to do this if you are intending to be namespace aware
+        # some services might not care what namespace the data is in, so long
+        # as there is data...
+    my @validNS_LSID = validateNamespaces("NCBI_gi");  # returns LSID's for each human-readable
+
+    foreach (@inputs){
+        my ($articleType, $qID, $input) = @{$_};
+        unless (($articleType == SIMPLE) && ($input)){
+                # in this example, we are only accepting SIMPLE types as input
+                # so write back an empty response block and move on to the next
+            $MOBY_RESPONSE .= simpleResponse("", "", $qID) ;
+            next;
+        } else {
+                # now take the namespace and ID from our input article
+                # (see pod docs for other possibilities)
+            my $namespace = getSimpleArticleNamespaceURI($input); # get namespace
+			my ($identifier) = getSimpleArticleIDs($input);  # get ID (note array output! see pod)
+			
+            # here is where you do whatever manipulation you need to do
+            # for your particular service.
+            # you will be building an XML document into $MOBY_RESPONSE            
         }
-     }
-   }
-   return responseHeader("my.authURI.com") . $MOBY_RESPONSE . responseFooter;
+    }
+    return SOAP::Data->type('base64' => (responseHeader("illuminae.com") . $MOBY_RESPONSE . responseFooter));    
  }
 
 =cut
@@ -72,46 +70,63 @@
 
 This is a service that:
 
-CONSUMES:  Object in the NCBI_Acc namespace
+CONSUMES:  base Object in the GO namespace
 EXECUTES:  Retrieval
-PRODUCES:  GenericSequence (in the NCBI_Acc namespace)
+PRODUCES:  GO_Term (in the GO namespace)
 
 
- use Bio::Perl;
- 
  # this subroutine is called from your dispatch_with line
  # in your SOAP daemon
- 
- sub myServiceName {
-   my ($caller, $message) = @_;  # get the incoming MOBY query XML
 
-   my @queries = getInputs($message);  # returns XML::DOM nodes
-   my $MOBY_RESPONSE = "";           # set empty response
- 
-   foreach my $query(@queries){
-
-     my $queryID = getInputID($query);  # get the queryID attribute of the queryInput
-     
-     my @input_articles = getArticles($query); # get the Simple/Collection articles making up this query
-     foreach my $input(@input_articles){       # input is a listref
-        my ($articleName, $article) = @{$input}; # get the named article
-        next unless isSimpleArticle($article);   # I only allow simple inputs in my service signature
-        my ($id) = getSimpleArticleIDs('NCBI_Acc', $article); # if you need the ID
-        my $seq;
-        eval {$seq = get_sequence('genbank',$id);} # suppress bioperl error messages
-        my $response = "";
-        if ($seq){
-            $length = length($seq);
-            $response = "<GenericSequence namespace='NCBI_Acc' id='$id'>
-                           <Integer namespace='' id='' articleName='Length'>$length</Integer>
-                           <String namespace='' id='' articleName='SequenceString'>$seq</String>
-                         </GenericSequence>";
-        }
-            $MOBY_RESPONSE .= simpleResponse($response, '', $queryID);
+
+ sub getGoTerm {
+    my ($caller, $message) = @_;
+    my $MOBY_RESPONSE;
+    my (@inputs)= genericServiceInputParser($message); # ([SIMPLE, $queryID, $simple],...)
+    return SOAP::Data->type('base64' => responseHeader('my.authURI.com') . responseFooter()) unless (scalar(@inputs));
+
+    my @validNS = validateNamespaces("GO");  # ONLY do this if you are intending to be namespace aware!
+
+    my $dbh = _connectToGoDatabase();
+    return SOAP::Data->type('base64' => responseHeader('my.authURI.com') . responseFooter()) unless $dbh;
+    my $sth = $dbh->prepare(q{
+       select name, term_definition
+       from term, term_definition
+       where term.id = term_definition.term_id
+       and acc=?});
+
+    foreach (@inputs){
+        my ($articleType, $ID, $input) = @{$_};
+        unless ($articleType == SIMPLE){
+            $MOBY_RESPONSE .= simpleResponse("", "", $ID);
+            next;
+        } else {
+			my $ns = getSimpleArticleNamespaceURI($input);
+			(($MOBY_RESPONSE .= simpleResponse("", "", $ID)) && (next))
+                   unless validateThisNamespace($ns, @validNS);  # only do this if you are truly validating namespaces
+			my ($accession) = defined(getSimpleArticleIDs($ns, [$input]))?getSimpleArticleIDs($ns,[$input]):undef;
+			unless (defined($accession)){
+				$MOBY_RESPONSE .= simpleResponse("", "", $ID);
+				next;
+			}
+			unless ($accession =~/^GO:/){
+				$accession = "GO:$accession";  # we still haven't decided on whether id's should include the prefix...
+			}
+			$sth->execute($accession);        
+			my ($term, $def) = $sth->fetchrow_array;
+			if ($term){
+				$MOBY_RESPONSE .= simpleResponse("
+					<moby:GO_Term namespace='GO' id='$accession'>
+						<moby:String namespace='' id='' articleName='Term'>$term</moby:String>
+						<moby:String namespace='' id='' articleName='Definition'>$def</moby:String>
+					</moby:GO_Term>", "GO_Term_From_ID", $ID)
+			} else {
+				$MOBY_RESPONSE .= simpleResponse("", "", $ID)
+			}
         }
-     }
-   }
-   return responseHeader("my.authURI.com") . $MOBY_RESPONSE . responseFooter;
+    }
+    
+    return SOAP::Data->type('base64' => (responseHeader("my.authURI.com") . $MOBY_RESPONSE . responseFooter));    
  }
 
 
@@ -121,7 +136,8 @@
 both Client and Service side to construct and parse MOBY Messages, and ensure
 that the message structure is valid as per the API.
 
-It DOES NOT connect to MOBY Central for any of its functions.
+It DOES NOT connect to MOBY Central for any of its functions, though it does
+contact the ontology server, so it will require a network connection.
 
 
 =head1 AUTHORS
@@ -148,11 +164,13 @@
 
 use constant COLLECTION => 1;
 use constant SIMPLE => 2;
+use constant SECONDARY => 3;
+use constant PARAMETER => 3;  # be friendly in case they use this instead
 use constant BE_NICE => 1;
 use constant BE_STRICT => 0;
 
 our @ISA = qw(Exporter);
-our @EXPORT = qw(COLLECTION SIMPLE BE_NICE BE_STRICT);
+our @EXPORT = qw(COLLECTION SIMPLE SECONDARY PARAMETER BE_NICE BE_STRICT);
 our @EXPORT_OK = qw(
     getSimpleArticleIDs
     getSimpleArticleNamespaceURI
@@ -175,10 +193,13 @@
     getResponseArticles
     getCrossReferences
     genericServiceInputParser
+    complexServiceInputParser
     whichDeepestParentObject
     getServiceNotes
     COLLECTION
     SIMPLE
+    SECONDARY
+    PARAMETER
     BE_NICE
     BE_STRICT
     );
@@ -204,40 +225,270 @@
     getResponseArticles
     getCrossReferences
     genericServiceInputParser
+    complexServiceInputParser
     whichDeepestParentObject
     getServiceNotes
     COLLECTION
     SIMPLE
+    SECONDARY
+    PARAMETER
     BE_NICE
     BE_STRICT
     )]);
 
 
 
+=head2 genericServiceInputParser
+
+ name     : genericServiceInputParser
+ function : For the MOST SIMPLE SERVICES that take single Simple or Collection inputs
+            and no Secondaries this routine takes the MOBY message and
+            breaks the objects out of it in a useful way
+ usage    : my @inputs = genericServiceInputParser($MOBY_mssage));
+ args     : $message - this is the SOAP payload; i.e. the XML document containing the MOBY message
+ returns  : @inputs - the structure of @inputs is a list of listrefs.
+            Each listref has three components:
+                1. COLLECTION|SIMPLE|SECONDARY (i.e. constants 1, 2, 3)
+                2. queryID (undef for Secondary parameters)
+                3. $data - the data takes several forms
+                         a. $article XML::DOM node for Simples
+                            <queryInput...>...</queryInput>
+                         b. \@article XML:DOM nodes for Collections
+                         c. $secondary XML::DOM node
+
+=cut
+
+
 sub genericServiceInputParser {
     my ($message) = @_;  # get the incoming MOBY query XML
     my @inputs;           # set empty response
-    my @queries = getInputs($message);  # returns XML::DOM nodes
+    my @queries = getInputs($message);  # returns XML::DOM nodes <queryInput>...</queryInput>
     
     foreach my $query(@queries){
         my $queryID = getInputID($query);  # get the queryID attribute of the queryInput
-        my @input_articles = getArticles($query); # get the Simple/Collection articles making up this query
+        my @input_articles = getArticles($query); # get the Simple/Collection/Secondary articles making up this query <Simple>...</Simple> or <Collection>...</Collection> or <Parameter>...</Parameter>
         foreach my $input(@input_articles){       # input is a listref
            my ($articleName, $article) = @{$input}; # get the named article
-           my $simple = isSimpleArticle($article);  # articles may be simple or collection
-           my $collection = isCollectionArticle($article);
-            if ($collection){
+            if (isCollectionArticle($article)){
                 my @simples = getCollectedSimples($article);
                 push @inputs, [COLLECTION,$queryID, \@simples];
+            } elsif (isSimpleArticle($article)){
+                push @inputs, [SIMPLE,$queryID,$article];
+            } elsif (isSecondaryArticle($article)){
+                push @inputs, [SECONDARY,$queryID,$article];
+            }
+        }
+    }
+    return @inputs;
+}
+
+
+
+
+=head2 complexServiceInputParser
+
+ name     : complexServiceInputParser
+ function : For more complex services taht have multiple articles for each input
+            and/or accept parameters, this routine will take a MOBY message and
+            extract the Simple/Collection/Parameter objects out of it in a
+            useful way.
+ usage    : my $inputs = complexServiceInputParser($MOBY_mssage));
+ args     : $message - this is the SOAP payload; i.e. the XML document containing the MOBY message
+ returns  : $inputs is a hashref with the following structure:
+            
+            $inputs->{$queryID} = [ [TYPE, $DOM], [TYPE, $DOM], [TYPE, $DOM] ]
+            
+            Simples ------------------------
+            
+            for example, the input message:
+            
+                <queryInput queryID = '1'>
+                    <Simple articleName='name1'>
+                       <Object namespace=blah id=blah/>
+                    </Simple>
+                    <Parameter articleName='cutoff'>
+                       <datatype>Float</datatype>
+                       <default>10</default>
+                    </Parameter>
+                </queryInput>
+
+            will become:
+            (note that SIMPLE, COLLECTION, and SECONDARY are exported constants from this module)
+            
+            $inputs->{1} = [ [SIMPLE, $DOM_name1],
+                             [SECONDARY, $DOM_cutoff]
+                           ]
+
+            Please see the XML::DOM pod documentation for information about how
+            to parse XML DOM objects.
+            
+            
+            Collections --------------------
+            
+            With inputs that have collections these are presented as a
+            listref of Simple article DOM's.  So for the following message:
+            
+                <queryInput>
+                    <Collection articleName='name1'>
+                      <Simple>
+                       <Object namespace=blah id=blah/>
+                      </Simple>
+                      <Simple>
+                       <Object namespace=blah id=blah/>
+                      </Simple>
+                    </Collection>
+                    <Parameter articleName='cutoff'>
+                       <datatype>Float</datatype>
+                       <default>10</default>
+                    </Parameter>
+                </queryInput>
+
+            will become
+            
+            $inputs->{1} = [ [COLLECTION, [$DOM, $DOM] ],
+                             [SECONDARY, $DOM_cutoff]
+                           ]
+
+            Please see the XML::DOM pod documentation for information about how
+            to parse XML DOM objects.
+
+
+=cut
+
+
+sub complexServiceInputParser {
+    my ($message) = @_;  # get the incoming MOBY query XML
+    my @inputs;           # set empty response
+    my @queries = getInputs($message);  # returns XML::DOM nodes <queryInput>...</queryInput>
+    my %input_parameters;  # $input_parameters{$queryID} = [
+    
+    foreach my $query(@queries){
+        my $queryID = getInputID($query);  # get the queryID attribute of the queryInput
+        my @input_articles = getArticles($query); # get the Simple/Collection/Secondary articles making up this query <Simple>...</Simple> or <Collection>...</Collection> or <Parameter>...</Parameter>
+        foreach my $input(@input_articles){       # input is a listref
+           my ($articleName, $article) = @{$input}; # get the named article
+            if (isCollectionArticle($article)){
+                my @simples = getCollectedSimples($article);
+                push @{$input_parameters{$queryID}}, [COLLECTION, \@simples];
+            } elsif (isSimpleArticle($article)){
+                push @{$input_parameters{$queryID}}, [SIMPLE, $article];
+            } elsif (isSecondaryArticle($article)){
+                push @{$input_parameters{$queryID}}, [SECONDARY, $article];
+            }
+        }
+    }
+    return \%input_parameters;
+}
+
+
+=head2 getArticles
+
+ name     : getArticles
+ function : get the Simple/Collection/Parameter articles for a single queryInput
+            or queryResponse node
+ usage    : @articles = getArticles($XML)
+ args     : raw XML or XML::DOM of a queryInput, mobyData, or queryResponse block (e.g. from getInputs)
+ returns  : a list of listrefs; each listref is one component of the queryInput.
+            a single queryInput/Response may consist of one or more named or unnamed
+            simple, collection, or parameter articles.
+            The listref structure is thus [name, $ARTICLE_DOM]:
+            
+    e.g.:  @articles = ['name1', $SIMPLE_DOM]
+
+            generated from the following sample XML:
+
+                <queryInput>
+                    <Simple articleName='name1'>
+                      <Object namespace=blah id=blah/>
+                    </Simple>
+                </queryInput>
+        
+    or  :  @articles = ['name1', $COLL_DOM], ['paramname1', $PARAM_DOM]
+
+            generated from the following sample XML:
+
+                <queryInput>
+                    <Collection articleName='name1'>
+                      <Simple>
+                       <Object namespace=blah id=blah/>
+                      </Simple>
+                      <Simple>
+                       <Object namespace=blah id=blah/>
+                      </Simple>
+                    </Collection>
+                    <Parameter articleName='e value cutoff'>
+                       <datatype>Float</datatype>
+                       <default>10</default>
+                    </Parameter>
+                </queryInput>
+
+=cut
+
+
+sub getArticles {
+
+	my ($moby) = @_;
+    unless (ref($moby) =~ /XML\:\:DOM/){
+        my $parser = new XML::DOM::Parser;
+        my $doc = $parser->parse($moby);
+        $moby = $doc->getDocumentElement();
+    }
+
+    return undef unless $moby->getNodeType == ELEMENT_NODE;
+    return undef unless (($moby->getTagName =~ /queryInput/) || ($moby->getTagName =~ /queryResponse/) || ($moby->getTagName =~ /mobyData/));
+    my @articles;
+    foreach my $child($moby->getChildNodes){ # there may be more than one Simple/Collection per input; iterate over them 
+        next unless $child->getNodeType == ELEMENT_NODE; # ignore whitespace
+        next unless ($child->getTagName =~ /Simple/ || $child->getTagName =~ /Collection/  || $child->getTagName =~ /Parameter/);
+        my $articleName = $child->getAttribute('articleName');
+        $articleName ||= $child->getAttribute('moby:articleName');
+        push @articles, [$articleName, $child];   # push the named child DOM elements (which are <Simple> or <Collection>, <Parameter>)
+    }
+	return @articles;  # return them.
+}
+
 
-            } elsif ($simple){
+
+=head2 genericServiceInputParserAsObject
+
+ name     : DO NOT USE!
+ function : to take a MOBY message and break the objects out of it.  This is identical
+            to the subroutine above, except that it returns the data as
+            Objects rather than XML::DOM nodes
+ usage    : my @inputs = genericServiceInputParser($MOBY_mssage));
+ args     : $message - this is the SOAP payload; i.e. the XML document containing the MOBY message
+ returns  : @inputs - the structure of @inputs is a list of listrefs.
+            Each listref has three components:
+                1. COLLECTION|SIMPLE|SECONDARY (i.e. constants 1, 2, 3)
+                2. queryID (undef for Secondary parameters)
+                3. $data - either MOBY::Client::SimpleArticle, CollectionArticle, or SecondaryArticle
+
+=cut
+
+
+sub genericServiceInputParserAsObject {
+    my ($message) = @_;  # get the incoming MOBY query XML
+    my @inputs;           # set empty response
+    my @queries = getInputs($message);  # returns XML::DOM nodes <queryInput>...</queryInput>
+    
+    foreach my $query(@queries){
+        my $queryID = getInputID($query);  # get the queryID attribute of the queryInput
+        my @input_articles = getArticlesAsObjects($query); # get the Simple/Collection articles making up this query <Simple>...</Simple> or <Collection>...</Collection> or <Parameter>...</Parameter
+        foreach my $article(@input_articles){       # input is a listref
+            if ($article->isCollection){
+                my @simples = getCollectedSimples($article->XML);
+                push @inputs, [COLLECTION,$queryID, \@simples];
+            } elsif ($article->isSimple){
                 push @inputs, [SIMPLE,$queryID,$article];
+            } elsif ($article->isSecondary){
+                push @inputs, [SECONDARY,$queryID,$article];
             }
         }
     }
     return @inputs;
 }
 
+
 #################################################
 					 ##################################
 					 ##################################
@@ -392,17 +643,16 @@
     $data ||='';  # initialize to avoid uninit value errors
     $qID ||="";
     $articleName ||="";
-    
     if ($articleName) {
         return "
         <moby:queryResponse moby:queryID='$qID'>
-            <moby:Simple articleName='$articleName'>$data</moby:Simple>
+            <moby:Simple moby:articleName='$articleName'>$data</moby:Simple>
         </moby:queryResponse>
         ";
     } elsif($data) {
         return "
         <moby:queryResponse moby:queryID='$qID'>
-            <moby:Simple articleName='$articleName'>$data</moby:Simple>
+            <moby:Simple moby:articleName='$articleName'>$data</moby:Simple>
         </moby:queryResponse>
         ";
     } else {
@@ -449,7 +699,7 @@
     $data ||=[];
     $qID ||= '';
     unless ((ref($data) =~ /array/i) && $data->[0]){  # we're expecting an arrayref as input data,and it must not be empty
-        return "<moby:queryResponse queryID='$qID'/>";
+        return "<moby:queryResponse moby:queryID='$qID'/>";
     }
 
     foreach (@{$data}){
@@ -465,7 +715,7 @@
     }
     if ($articleName) {
         return "
-        <moby:queryResponse queryID='$qID'>
+        <moby:queryResponse moby:queryID='$qID'>
             <moby:Collection moby:articleName='$articleName'>
                 $content
             </moby:Collection>
@@ -473,7 +723,7 @@
         ";
     } else {
         return "
-        <moby:queryResponse queryID='$qID'>
+        <moby:queryResponse moby:queryID='$qID'>
             <moby:Collection moby:articleName='$articleName'>$content</moby:Collection>
         </moby:queryResponse>
         ";
@@ -545,8 +795,8 @@
  function : get the queryInput block(s) as XML::DOM nodes
  usage    : @queryInputs = getInputArticles($XML)
  args     : the raw XML of a <MOBY> query, or an XML::DOM document
- returns  : a list of XML::DOM::Node's, each is a queryInput.
- Note     : Remember that queryInputs are numbered!  This is what you
+ returns  : a list of XML::DOM::Node's, each is a queryInput or mobyData block.
+ Note     : Remember that these blocks are enumerated!  This is what you
             pass as the third argument to the simpleResponse or collectionResponse
             subroutine to associate the numbered input to the numbered response
 
@@ -562,16 +812,14 @@
         my $doc = $parser->parse($XML);
         $moby = $doc->getDocumentElement();
     }
+    my @queries;
 
-    my $x = $moby->getElementsByTagName('queryInput');  # get the queryInput block
-    unless ($x->item(0)){
-		$x = $moby->getElementsByTagName('moby:queryInput');
+    foreach my $querytag('queryInput', 'moby:queryInput', 'mobyData', 'moby:mobyData'){
+        my $x = $moby->getElementsByTagName($querytag);  # get the queryInput block
+        for (0..$x->getLength-1){ # there may be more than one queryInput per message
+            push @queries, $x->item($_);
+        }
     }
-
-    my @queries;
-    for (0..$x->getLength-1){ # there may be more than one queryInput per message
-        push @queries, $x->item($_);
-	}
 	return @queries;  # return them in the order that they were discovered.
 }
 
@@ -581,9 +829,9 @@
  name     : getInputID
  function : get the value of the queryID element
  usage    : @queryInputs = getInputID($XML)
- args     : the raw XML or XML::DOM of a <queryInput> block
+ args     : the raw XML or XML::DOM of a queryInput or mobyData block (e.g. from getInputs)
  returns  : integer, or ''
- Note     : queryInputs and queryResponses are coordinately enumerated!
+ Note     : Inputs and Responses are coordinately enumerated!
             The integer you get here is what you
             pass as the third argument to the simpleResponse or collectionResponse
             subroutine to associate the numbered input to the numbered response
@@ -598,44 +846,61 @@
         my $doc = $parser->parse($XML);
         $XML = $doc->getDocumentElement();
     }
-    return '' unless $XML->getTagName =~ /queryInput/;
+    return '' unless (($XML->getTagName =~ /queryInput/) || ($XML->getTagName =~ /mobyData/));
     my $qid = $XML->getAttribute('queryID');
+    $qid ||= $XML->getAttribute('moby:queryID');
+    
     return defined($qid)?$qid:'';
 }
 
 
 
-=head2 getArticles
+=head2 getArticlesAsObjects
 
- name     : getArticles
+ name     : getArticlesAsObjects
  function : get the Simple/Collection articles for a single queryInput
-            or queryResponse node
+            or queryResponse node, rethrning them as SimpleArticle,
+            SecondaryArticle, or ServiceInstance objects
  usage    : @articles = getArticles($XML)
- args     : raw XML or XML::DOM of a moby:queryInput or a moby:queryResponse block
+ args     : raw XML or XML::DOM of a moby:queryInput, moby:queryResponse block
  returns  : a list of listrefs; each listref is one component of the queryInput.
-            a single queryInput/Responsemay consist of one or more named or unnamed
-            simple or collection articles.  The listref structure is thus [name, $ARTICLE]:
+            a single queryInput/Response may consist of one or more named or unnamed
+            simple, collection, or parameter articles.
+            The listref structure is thus [name, $ARTICLE_OBJECT]:
             
-            e.g.:  @articles = ['name1', $SIMPLE_DOM]
-            or  :  @articles = ['name1', $COLLECTION_DOM], ['name2', $SIMPLE_DOM]...
+    e.g.:  @articles = ['name1', $SimpleArticle]
 
-            the former is generated from the following sample XML:
+            generated from the following sample XML:
 
                 <queryInput>
                     <Simple articleName='name1'>
                       <Object namespace=blah id=blah/>
                     </Simple>
                 </queryInput>
+        
+    or  :  @articles = ['name1', $CollectionArticle], ['paramname1', $SecondaryArticle]
+
+            generated from the following sample XML:
+
                 <queryInput>
-                    <Simple articleName='name1'>
-                      <Object namespace=blah id=blah/>
-                    </Simple>
+                    <Collection articleName='name1'>
+                      <Simple>
+                       <Object namespace=blah id=blah/>
+                      </Simple>
+                      <Simple>
+                       <Object namespace=blah id=blah/>
+                      </Simple>
+                    </Collection>
+                    <Parameter articleName='e value cutoff'>
+                       <datatype>Float</datatype>
+                       <default>10</default>
+                    </Parameter>
                 </queryInput>
 
 =cut
 
 
-sub getArticles {
+sub getArticlesAsObjects {
 
 	my ($moby) = @_;
     unless (ref($moby) =~ /XML\:\:DOM/){
@@ -645,14 +910,21 @@
     }
 
     return undef unless $moby->getNodeType == ELEMENT_NODE;
-    return undef unless ($moby->getTagName =~ /queryInput/ || $moby->getTagName =~ /queryResponse/);
+    return undef unless (($moby->getTagName =~ /queryInput/) || ($moby->getTagName =~ /queryResponse/) || ($moby->getTagName =~ /mobyData/));
     my @articles;
     foreach my $child($moby->getChildNodes){ # there may be more than one Simple/Collection per input; iterate over them 
         next unless $child->getNodeType == ELEMENT_NODE; # ignore whitespace
-        next unless ($child->getTagName =~ /Simple/ || $child->getTagName =~ /Collection/);
-        my $articleName = $child->getAttribute('articleName');
-        $articleName ||= $child->getAttribute('moby:articleName');
-        push @articles, [$articleName, $child];   # take the child elements, which are <Simple/> or <Collection/>
+        next unless ($child->getTagName =~ /Simple/ || $child->getTagName =~ /Collection/  || $child->getTagName =~ /Parameter/);
+        my $object;
+        if ($child->getTagName =~ /Simple/){
+            $object = MOBY::Client::SimpleArticle->new(XML_DOM => $child);
+        } elsif ($child->getTagName =~ /Collection/){
+            $object = MOBY::Client::CollectionArticle->new(XML_DOM => $child);
+        } elsif ($child->getTagName =~ /Parameter/){
+            $object = MOBY::Client::CollectionArticle->new(XML_DOM => $child);
+        }
+        next unless $object;
+        push @articles, $object;   # take the child elements, which are <Simple/> or <Collection/>
     }
 	return @articles;  # return them.
 }
@@ -707,18 +979,18 @@
             the former is generated from the following XML:
             
                 ...
-              <moby:Query>
-                <queryInput>
+              <moby:mobyContent>
+                <moby:mobyData>
                     <Simple>
                       <Object namespace=blah id=blah/>
                     </Simple>
-                </queryInput>
-                <queryInput>
+                </moby:mobyData>
+                <moby:mobyData>
                     <Simple>
                       <Object namespace=blah id=blah/>
                     </Simple>
-                </queryInput>
-              </moby:Query>
+                </moby:mobyData>
+              </moby:mobyContent>
                  ...
 
 =cut
@@ -733,11 +1005,13 @@
         $moby = $doc->getDocumentElement();
     }
 
-    my $x = $moby->getElementsByTagName('queryInput');  # get the queryInput block
-    unless ($x->item(0)){
-		$x = $moby->getElementsByTagName('moby:queryInput');
+    my $x;
+    foreach ('queryInput', 'moby:queryInput', 'mobyData', 'moby:mobyData'){
+        $x = $moby->getElementsByTagName($_);  # get the queryInput block
+        last if $x->item(0);
     }
-
+    return undef unless $x->item(0); # in case there was no match at all
+    
     my @queries;
     for (0..$x->getLength-1){ # there may be more than one queryInput per message
 		my @this_query;
@@ -750,6 +1024,7 @@
 	return @queries;  # return them in the order that they were discovered.
 }
 
+
 =head2 isSimpleArticle
 
  name     : isSimpleArticle
@@ -798,6 +1073,57 @@
     return 0;
 }
 
+
+=head2 isSecondaryArticle
+
+ name     : isSecondaryArticle
+ function : tests XML (text) or an XML DOM node to see if it represents a Secondary article
+ usage    : if (isSecondaryArticle($node)){do something to it}
+ input    : an XML::DOM node, an XML::DOM::Document or straight XML
+ returns  : boolean
+
+=cut
+
+sub isSecondaryArticle {
+    my ($DOM) = @_;
+    unless (ref($DOM) =~ /XML\:\:DOM/){
+        my $parser = new XML::DOM::Parser;
+        my $doc;
+        eval {$doc = $parser->parse($DOM);};
+        return 0 if ($@);
+        $DOM = $doc->getDocumentElement();
+    }
+    $DOM = $DOM->getDocumentElement if ($DOM->isa("XML::DOM::Document"));
+    return 1 if ($DOM->getTagName =~ /Parameter/);
+    return 0;
+}
+
+
+=head2 extractRawContent
+
+ name     : extractRawContent
+ function : pass me an article (Simple, or Collection) and I'll give you the
+            content AS A STRING - i.e. the raw XML of the contained MOBY Object(s)
+ usage    : extractRawContent($simple)
+ input    : the one element of the output from getArticles
+ returns  : string
+
+=cut
+
+
+sub extractRawContent {
+    my ($article) = @_;
+    return "" unless $article;
+    return "" unless ref($article) =~ /XML::DOM/;
+    my $response;
+    foreach ($article->getChildNodes){
+        $response .= $_->toString;
+    }
+    return $response;
+    
+}
+
+
 =head2 getNodeContentWithArticle
 
  name     : getNodeContentWithArticle
@@ -815,16 +1141,16 @@
             For example, in the following XML:
              ...
              ...
-             <moby:Query>
-                <queryInput>
+             <moby:mobyContent>
+                <moby:mobyData>
                     <Simple>
                       <Sequence namespace=blah id=blah>
                            <Integer namespace='' id='' articleName="Length">3</Integer>
                            <String namespace='' id='' articleName="SequenceString">ATG</String>
                       </Sequence>
                     </Simple>
-                </queryInput>
-             </moby:Query>
+                </moby:mobyData>
+             </moby:mobyContent>
              ...
              ...
              
@@ -843,32 +1169,6 @@
 
 =cut
 
-
-=head2 extractRawContent
-
- name     : extractRawContent
- function : pass me an article (Simple, or Collection) and I'll give you the
-            content AS A STRING - i.e. the raw XML of the contained MOBY Object(s)
- usage    : extractRawContent($simple)
- input    : the one element of the output from getArticles
- returns  : string
-
-=cut
-
-
-sub extractRawContent {
-    my ($article) = @_;
-    return "" unless $article;
-    return "" unless ref($article) =~ /XML::DOM/;
-    my $response;
-    foreach ($article->getChildNodes){
-        $response .= $_->toString;
-    }
-    return $response;
-    
-}
-
-
 sub getNodeContentWithArticle{
 	# give me a DOM, a TagName, an articleName and I will return you the content
 	# of that node **as a string** (beware if there are additional XML tags in there!)
@@ -989,30 +1289,32 @@
     my @collections;
     my @Xrefs;
     my $success = 0;
-    my $responses = $moby->getElementsByTagName('moby:queryResponse');
-    $responses ||= $moby->getElementsByTagName('queryResponse');
-    foreach my $n(0..($responses->getLength - 1)){
-        my $resp = $responses->item($n);
-        foreach my $response_component($resp->getChildNodes){ 
-            next unless $response_component->getNodeType == ELEMENT_NODE;
-            if (($response_component->getTagName eq "Simple") || ($response_component->getTagName eq "moby:Simple")){
-                foreach my $Object($response_component->getChildNodes) {
-                    next unless $Object->getNodeType == ELEMENT_NODE;
-                    $success = 1;
-                    push @objects,$Object;
-                }
-            } elsif (($response_component->getTagName eq "Collection") || ($response_component->getTagName eq "moby:Collection")){
-                my @objects;
-                foreach my $simple($response_component->getChildNodes){
-                    next unless $simple->getNodeType == ELEMENT_NODE;
-                    next unless (($simple->getTagName eq "Simple") || ($simple->getTagName eq "moby:Simple"));
-                    foreach my $Object($simple->getChildNodes) {
+    foreach my $which ('moby:queryResponse', 'queryResponse', 'mobyData', 'moby:mobyData'){
+        my $responses = $moby->getElementsByTagName($which);
+        next unless $responses;
+        foreach my $n(0..($responses->getLength - 1)){
+            my $resp = $responses->item($n);
+            foreach my $response_component($resp->getChildNodes){ 
+                next unless $response_component->getNodeType == ELEMENT_NODE;
+                if (($response_component->getTagName eq "Simple") || ($response_component->getTagName eq "moby:Simple")){
+                    foreach my $Object($response_component->getChildNodes) {
                         next unless $Object->getNodeType == ELEMENT_NODE;
                         $success = 1;
                         push @objects,$Object;
                     }
+                } elsif (($response_component->getTagName eq "Collection") || ($response_component->getTagName eq "moby:Collection")){
+                    my @objects;
+                    foreach my $simple($response_component->getChildNodes){
+                        next unless $simple->getNodeType == ELEMENT_NODE;
+                        next unless (($simple->getTagName eq "Simple") || ($simple->getTagName eq "moby:Simple"));
+                        foreach my $Object($simple->getChildNodes) {
+                            next unless $Object->getNodeType == ELEMENT_NODE;
+                            $success = 1;
+                            push @objects,$Object;
+                        }
+                    }
+                    push @collections, \@objects;    #I'm not using collections yet, so we just use Simples.
                 }
-                push @collections, \@objects;    #I'm not using collections yet, so we just use Simples.
             }
         }
     }




More information about the MOBY-guts mailing list