<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.opendap.org/index.php?action=history&amp;feed=atom&amp;title=ProgrammerGuideChapter4-2</id>
	<title>ProgrammerGuideChapter4-2 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://docs.opendap.org/index.php?action=history&amp;feed=atom&amp;title=ProgrammerGuideChapter4-2"/>
	<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=ProgrammerGuideChapter4-2&amp;action=history"/>
	<updated>2026-04-20T13:12:32Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.38.4</generator>
	<entry>
		<id>https://docs.opendap.org/index.php?title=ProgrammerGuideChapter4-2&amp;diff=1194&amp;oldid=prev</id>
		<title>Yuan: New page: ==Client Libraries==   The goal of building a client library is to provide a drop-in replacement for an existing API so that user programs written for that API can switch to the OPeNDAP ve...</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=ProgrammerGuideChapter4-2&amp;diff=1194&amp;oldid=prev"/>
		<updated>2007-09-28T01:08:33Z</updated>

		<summary type="html">&lt;p&gt;New page: ==Client Libraries==   The goal of building a client library is to provide a drop-in replacement for an existing API so that user programs written for that API can switch to the OPeNDAP ve...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==Client Libraries==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The goal of building a client library is to provide a drop-in&lt;br /&gt;
replacement for an existing API so that user programs written for that&lt;br /&gt;
API can switch to the OPeNDAP version and access remote OPeNDAP data. The&lt;br /&gt;
user programs should not require any modification to change over to&lt;br /&gt;
the OPeNDAP client library version of the API. However, the API will&lt;br /&gt;
clearly need substantial changes to its current implementation.&lt;br /&gt;
&lt;br /&gt;
In order to build the OPeNDAP client library for a particular API, it is&lt;br /&gt;
useful to divide the API to be re-implemented into five categories of&lt;br /&gt;
functions:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Open or connect&lt;br /&gt;
*Variable information read&lt;br /&gt;
*Data read&lt;br /&gt;
*Write&lt;br /&gt;
*Close or disconnect&lt;br /&gt;
&lt;br /&gt;
===Rewriting the Open and Close Functions===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The functions that perform the dataset &amp;quot;open&amp;quot; and &amp;quot;close&amp;quot;&lt;br /&gt;
operations must be implemented so that information about the data set&lt;br /&gt;
can be retrieved from the data server. These functions must store the&lt;br /&gt;
necessary state information so that subsequent accesses for variable&lt;br /&gt;
information or data reads can be satisfied. This state information&lt;br /&gt;
will, in almost every case, be the dataset&amp;#039;s DAS and&lt;br /&gt;
DDS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The open function for a OPeNDAP client library version of a given&lt;br /&gt;
API must first determine if the data object (typically a file) is&lt;br /&gt;
local to the user program making the open call or is a remote data&lt;br /&gt;
object to be accessed through OPeNDAP. It is possible to access OPeNDAP&lt;br /&gt;
objects which are local to a user program, but there is little reason&lt;br /&gt;
to do so if the data object can also be accessed through the original&lt;br /&gt;
API. In any case, the distinction of local or remote is made on the&lt;br /&gt;
basis whether a URL is used to reference the data object, or a local&lt;br /&gt;
filename.&lt;br /&gt;
&lt;br /&gt;
If the data object is remote, then the open function must build a&lt;br /&gt;
structure which can hold the DAS  and  DDS objects which&lt;br /&gt;
describe the named data set.  This is the Connect class&lt;br /&gt;
object.  Once this object is built, the open function must map this&lt;br /&gt;
structure to a file identifier or pointer which can be passed back to&lt;br /&gt;
the user program as the return value of the open function. You add&lt;br /&gt;
this data to the Connect objects when you sub-class them for a&lt;br /&gt;
particular API.  Subsequent accesses to the data set will include this&lt;br /&gt;
identifier (or pointer), and each function that is a member of the API&lt;br /&gt;
can be modified to use it to gain access to the state information&lt;br /&gt;
stored by the open function.&lt;br /&gt;
&lt;br /&gt;
The close function should use the state information accessible with&lt;br /&gt;
the file identifier or pointer returned by the open function to&lt;br /&gt;
determine if the dataset is local or remote. In the case of a local&lt;br /&gt;
data set, the original implementation&amp;#039;s close function must be&lt;br /&gt;
called. In the case of a remote data set, the locally stored state&lt;br /&gt;
information must be freed.  You can do this by destroying the&lt;br /&gt;
Connect object.&lt;br /&gt;
&lt;br /&gt;
See ([http://www &amp;lt;cite&amp;gt; tk,subclass-netio&amp;lt;/cite&amp;gt;]) for an example of a recoded open&lt;br /&gt;
function and a description of its use.  (The example uses the \netcdf\&lt;br /&gt;
API.)&lt;br /&gt;
&lt;br /&gt;
===Getting Information about Variables===&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Most APIs for self-describing data sets include functions which return&lt;br /&gt;
information about the variables that comprise a data set. These&lt;br /&gt;
functions return information about the type and shape of variables in&lt;br /&gt;
a form that can be used by a program as well as attribute information&lt;br /&gt;
about the variables that is more often than not intended for use by&lt;br /&gt;
humans. Each of these functions must be rewritten so that to the&lt;br /&gt;
extent possible, information present in the DAS and&lt;br /&gt;
DDS is used to satisfy them.&lt;br /&gt;
&lt;br /&gt;
While many `self-describing&amp;#039; APIs may have dozens of&lt;br /&gt;
these functions, the basic structure of the re-implemented code is the same&lt;br /&gt;
for each one. If the data set is local, use the original implementation,&lt;br /&gt;
otherwise use the locally stored state information (DAS and&lt;br /&gt;
DDS) to answer the request for data.&lt;br /&gt;
&lt;br /&gt;
Rewriting these functions can be the most labor intensive part of&lt;br /&gt;
re-imple\-menting a given API. This is typically the largest group of&lt;br /&gt;
functions in the API and the information stored in the DAS and&lt;br /&gt;
DDS must often be `massaged&amp;#039; before it fulfills the&lt;br /&gt;
specifications of the API. Thus the rewritten functions must not only&lt;br /&gt;
get the necessary information from the DAS  and  DDS&lt;br /&gt;
objects, but they must also transform the types of the objects used to&lt;br /&gt;
return that information to the user program into the data types the&lt;br /&gt;
program expects.&lt;br /&gt;
&lt;br /&gt;
===Reading the Values of Variables from a Dataset===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To read data values from a dataset using a typical data access API, a&lt;br /&gt;
user would submit to some API function the name of the variable to be&lt;br /&gt;
read.  The OPeNDAP client library version of this same function must take&lt;br /&gt;
that variable name and use it to construct a constraint expression.&lt;br /&gt;
(See Section~(tk,using-constraints) for more information on using&lt;br /&gt;
constraint expressions to access data.)  The constraint expression&lt;br /&gt;
must then be appended to the dataset URL (with the suffix&lt;br /&gt;
&amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;.dods&amp;lt;/font&amp;gt;), and the resulting URL sent out into the internet.&lt;br /&gt;
&lt;br /&gt;
For example, to get a variable called &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;var&amp;lt;/font&amp;gt; from a dataset at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://blah/cgi-bin/nph-nc/weekly.nc.dods&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
\noindent~you would use the URL:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://blah/cgi-bin/nph-nc/weekly.nc.dods?var&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The Connect class contains a member function,&lt;br /&gt;
&amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;request_data&amp;lt;/font&amp;gt; that performs this task. It takes the constraint&lt;br /&gt;
expression and the suffix to use for requesting data, appends them to&lt;br /&gt;
the Connect URL, and sends the entire string off to retrieve&lt;br /&gt;
its corresponding data.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;request_data&amp;lt;/font&amp;gt; function returns a pointer to a DDS&lt;br /&gt;
object, which contains the data as well as the structure description&lt;br /&gt;
corresponding to the data request.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once the &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;request_data&amp;lt;/font&amp;gt; member function has returned, the client&lt;br /&gt;
library must still call the &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;deserialize&amp;lt;/font&amp;gt; member function (which&lt;br /&gt;
is part of the OPeNDAP Type Classes) for each returned variable. The&lt;br /&gt;
client library should use the variable objects contained in the&lt;br /&gt;
DDS object returned by &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;request_data&amp;lt;/font&amp;gt; to invoke the&lt;br /&gt;
&amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;deserialize&amp;lt;/font&amp;gt; member function. Once that is done, the data values&lt;br /&gt;
are stored in the internal buffers of the variable objects in the new&lt;br /&gt;
DDS \footnote{For the  Sequence data type, the&lt;br /&gt;
DDS contains only the current instance of the data.&lt;br /&gt;
Repeated calls to the Sequence&amp;#039;s &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;deserialize&amp;lt;/font&amp;gt; function&lt;br /&gt;
are required to return successive instances of the sequence.}. The&lt;br /&gt;
client library should store this new DDS, along with the&lt;br /&gt;
constraint expression passed to &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;request_data&amp;lt;/font&amp;gt; so that future&lt;br /&gt;
requests by the user program for the same information can be handled&lt;br /&gt;
without accessing the remote data server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The data values of variables in a DDS are accessed using the&lt;br /&gt;
&amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;buf2val&amp;lt;/font&amp;gt; member function for the cardinal and vector types and by&lt;br /&gt;
accessing the values of fields for constructor types.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Translation====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a OPeNDAP client library to be robust, it may have to be equipped to&lt;br /&gt;
deal with data types it was not designed to use.  For example, the&lt;br /&gt;
\netcdf software cannot manipulate a OPeNDAP Sequence.  But a user can&lt;br /&gt;
use the OPeNDAP version of the \netcdf library to request data from a&lt;br /&gt;
server that provides Sequence data.  When cases like this arise (and&lt;br /&gt;
they arise farily often), the author of the client library must choose&lt;br /&gt;
an appropriate data type into which the served data is to be&lt;br /&gt;
translated, and implement functions to do that translation.&lt;br /&gt;
&lt;br /&gt;
Often, translation from one data type to another is a simple&lt;br /&gt;
task. Translating an Array into Sequence format is fairly&lt;br /&gt;
straightforward, although there are several ways to do it. (The&lt;br /&gt;
author of the client library should choose one, and document that&lt;br /&gt;
choice in a README file.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Other translations are more complex, and may even require that the&lt;br /&gt;
client library violate the semantics of the original API, or of one of&lt;br /&gt;
the OPeNDAP data types.  For example, translating a Sequence to an Array&lt;br /&gt;
in \netcdf requires that the client know in advance the length of the&lt;br /&gt;
Sequence, which is not necessarily known.&lt;br /&gt;
&lt;br /&gt;
===Functions that Write to Data Sets===&lt;br /&gt;
&lt;br /&gt;
OPeNDAP is a read-only data system. While it is not technically&lt;br /&gt;
inconceivable, a system which allows modification of remote data sets&lt;br /&gt;
would be operationally much more complex than OPeNDAP. Thus, functions&lt;br /&gt;
that write data are rewritten so that they call the original&lt;br /&gt;
implementation in the case of a local access or return an error code&lt;br /&gt;
in the case of a remote access. The error code should indicate a&lt;br /&gt;
recoverable error so that programs which perform both reads and writes&lt;br /&gt;
can recover if their logic permits.&lt;br /&gt;
&lt;br /&gt;
===Adding Local Access to a OPeNDAP Client Library===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In order to ensure that programs, once they have been re-linked with&lt;br /&gt;
OPeNDAP client libraries, can still access local data files it is&lt;br /&gt;
necessary to add software to read those local data to the functions in&lt;br /&gt;
the re-implemented library. Typically in each function in the new&lt;br /&gt;
library the state information accessed by the identifier passed to the&lt;br /&gt;
function is used to determine if the call is to access local or remote&lt;br /&gt;
data. In the former case, the function must do exactly what the&lt;br /&gt;
original implementation of the API would have done to satisfy the&lt;br /&gt;
function call.&lt;br /&gt;
&lt;br /&gt;
It is wasteful to completely recode the entire API just to achieve&lt;br /&gt;
local access.  However, it is also not possible to simply link the&lt;br /&gt;
user program with both the OPeNDAP client library and the original&lt;br /&gt;
library. because both libraries must \emph{define the same external&lt;br /&gt;
  symbols}. Linking with both libraries will produce link-time&lt;br /&gt;
conflicts on most computers or result in an incorrectly linked binary&lt;br /&gt;
image.&lt;br /&gt;
&lt;br /&gt;
In order to use the original implementation of the library, you must&lt;br /&gt;
rename all of its external symbols that will appear in user programs.&lt;br /&gt;
For example, if an API defines four functions (&amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;open&amp;lt;/font&amp;gt;,&lt;br /&gt;
&amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;close&amp;lt;/font&amp;gt;, &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;read&amp;lt;/font&amp;gt; and &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;write&amp;lt;/font&amp;gt;) and one global variable&lt;br /&gt;
(&amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;errno&amp;lt;/font&amp;gt;), then each of those must be renamed to some new symbol&lt;br /&gt;
(e.g., &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;orig_open&amp;lt;/font&amp;gt;, &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;orig_close&amp;lt;/font&amp;gt;, \ldots). These source&lt;br /&gt;
modules can then be added to the set of object modules used to build&lt;br /&gt;
the OPeNDAP client library. Of course the OPeNDAP client library must also&lt;br /&gt;
include the original external symbol names; one approach is to recode&lt;br /&gt;
each of the APIs external symbols as a function which either calls the&lt;br /&gt;
OPeNDAP-replacement or the original function (now renamed so that the&lt;br /&gt;
symbols do not conflict) depending on whether the access is local or&lt;br /&gt;
remote.&lt;br /&gt;
&lt;br /&gt;
==Using Constraints==&lt;br /&gt;
&lt;br /&gt;
Constraint expressions are an important part of OPeNDAP, providing a&lt;br /&gt;
powerful way to control how data is accessed without forcing the \Dap&lt;br /&gt;
to support a lot of different messages. Constraint expressions are&lt;br /&gt;
used to select which variables will be extracted from a data set by&lt;br /&gt;
both the user and by the client library.  The constraint expression&lt;br /&gt;
syntax is described in detail in the [http://www.opendap.org/support/docs.html/user/guide-html/&amp;lt;cite&amp;gt;The OPeNDAP User Guide&amp;lt;/cite&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===How Constraint Expressions are Evaluated===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The server-side constraint expressions are evaluated using a two step&lt;br /&gt;
process. Every constraint expression has two parts, the projection and&lt;br /&gt;
the selection subexpressions. The projection part of a constraint&lt;br /&gt;
expression tells which variables to include in any return document&lt;br /&gt;
describing the data set and the selection subexpression limits the&lt;br /&gt;
returned data to variables with values that satisfy a set of&lt;br /&gt;
relational expressions.  The projection subexpression is evaluated&lt;br /&gt;
when the entire constraint expression is parsed; at parse-time the&lt;br /&gt;
server&amp;#039;s copy of the data set&amp;#039;s DDS is marked with the&lt;br /&gt;
variables included in the projection. The selection subexpression,&lt;br /&gt;
however, is not evaluated until values are read from the data set. One&lt;br /&gt;
way to classify the projection and selection subexpressions is that&lt;br /&gt;
projections depend solely on the logical structure of a data set,&lt;br /&gt;
while selections depend on the values of particular variables within&lt;br /&gt;
that data set.&lt;br /&gt;
&lt;br /&gt;
===Different Ways of Using Constraint Expressions===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are two different ways that constraint expressions can be used.&lt;br /&gt;
One is by the client library and the other is by the user. When&lt;br /&gt;
writing a client library that has features for selecting variables or&lt;br /&gt;
parts of variables, try to code the replacements to those calls so&lt;br /&gt;
that they build up OPeNDAP constraint expressions that will request only&lt;br /&gt;
the data the user wants. Then read the data from the returned DDS and&lt;br /&gt;
store it in the variable(s) passed to the API call by the user. This&lt;br /&gt;
is a much better solution than requesting the entire variable from the&lt;br /&gt;
data set and then throwing away parts of it.&lt;br /&gt;
&lt;br /&gt;
Suppose that the user program (via the APIs functional interface) asks&lt;br /&gt;
for the data in variable \var{X}. The constraint expression that will&lt;br /&gt;
retrieve \var{X} is simply `\var{X}&amp;#039;. Suppose, given the following&lt;br /&gt;
DDS}that the user program requests the two variables \var{u&lt;br /&gt;
and \var{v} from the embedded structure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dataset {&lt;br /&gt;
    Int32 u[time_a = 16][lat = 17][lon = 21];&lt;br /&gt;
    Int32 v[time_a = 16][lat = 17][lon = 21];&lt;br /&gt;
    Float64 lat[lat = 17];&lt;br /&gt;
    Float64 lon[lon = 21];&lt;br /&gt;
    Float64 time[time = 16];&lt;br /&gt;
} fnoc1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A constraint expression that would project just those variables would&lt;br /&gt;
be &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;fnoc1.u,fnoc1.v&amp;lt;/font&amp;gt;. To restrict the arrays \var{u} and \var{v}&lt;br /&gt;
to only the first two dimensions (&amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;time&amp;lt;/font&amp;gt; and &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;lat&amp;lt;/font&amp;gt;), the&lt;br /&gt;
projection subexpression would be:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fnoc1.u[0:15][0:16],fnoc1.v[0:15][0:16]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both of these&lt;br /&gt;
constraint expressions have null selection subexpressions. Note that&lt;br /&gt;
the comma operator separates the two clauses of the projection&lt;br /&gt;
subexpression. Also note that whitespace is ignored by the constraint&lt;br /&gt;
expression parser. See the grammar for CEs in the [http://www.opendap.org/support/docs.html/user/guide-html/&amp;lt;cite&amp;gt;The OPeNDAP User Guide&amp;lt;/cite&amp;gt;] for more&lt;br /&gt;
information about constraint expression grammar and the kind of things&lt;br /&gt;
that can be done with the projection subexpression.&lt;br /&gt;
&lt;br /&gt;
The user program may have an interface that provides the user with a&lt;br /&gt;
way to request only certain values be returned. This is particularly&lt;br /&gt;
true for APIs such as JGOFS that support access to relational data&lt;br /&gt;
sets. Suppose the following DDS describes a relational data&lt;br /&gt;
set:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dataset {&lt;br /&gt;
    Sequence {&lt;br /&gt;
        Int32 id;&lt;br /&gt;
        Float64 lat;&lt;br /&gt;
        Float64 lon;&lt;br /&gt;
        Sequence {&lt;br /&gt;
            Float64 depth;&lt;br /&gt;
            Float64 temperature;&lt;br /&gt;
        } xbt;&lt;br /&gt;
    } site;&lt;br /&gt;
} cruise;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To request data with a certain range of latitude&lt;br /&gt;
and longitude values, you can use a selection subexpression like&lt;br /&gt;
this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;amp; lat&amp;gt;=10.0 &amp;amp; lat&amp;lt;=20.0 &amp;amp; long&amp;gt;=5.5 &amp;amp; long&amp;lt;=7.5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that each clause of the selection subexpression begins with a&lt;br /&gt;
&amp;#039;&amp;#039;\&amp;amp;\/&amp;#039;&amp;#039;  and that the clauses are combined using a boolean&lt;br /&gt;
&amp;#039;&amp;#039;and&amp;#039;&amp;#039; .  Finally, using the previous DDS, if a user&lt;br /&gt;
requested only depth and temperature given the above latitude and&lt;br /&gt;
longitude range (i.e., the user program requests that only the depth&lt;br /&gt;
and temperature values be returned given a certain latitude and&lt;br /&gt;
longitude range) the client library would use the following constraint&lt;br /&gt;
expression:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
site.xbt.depth, site.xbt.temp &amp;amp; lat&amp;gt;=10.0 &amp;amp; lat&amp;lt;=20.0 &amp;amp;&lt;br /&gt;
   long&amp;gt;=5.5 &amp;amp; long&amp;lt;=7.5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A second way that constraint expressions can be used is that users may&lt;br /&gt;
specify an initial URL with a constraint expression already attached.&lt;br /&gt;
In this case the &amp;lt;font color=&amp;#039;green&amp;#039;&amp;gt;request_data&amp;lt;/font&amp;gt; member function will append the&lt;br /&gt;
constraint expression built by the client library to the one supplied&lt;br /&gt;
by the user and request data constrained by both expressions.  From&lt;br /&gt;
the standpoint of a client library (or a data server, for that matter)&lt;br /&gt;
there is no difference between a URL supplied with an initial&lt;br /&gt;
constraint and one supplied without one.&lt;/div&gt;</summary>
		<author><name>Yuan</name></author>
	</entry>
</feed>