The Jangle Core is the Atom Publishing Protocol interface to Jangle. It enables clients to access and (eventually) create and modify library resources RESTfully using regular AtomPub libraries (and conventions). The core also serves as the mediator between the client and the connector, receiving incoming requests, brokering them to the appropriate connector, parsing the JSON responses and serializing them into appropriate XML documents (Atom Syndication Format, Atom Services documents, OpenSearch Description documents, etc.).
A Jangle application does not need to follow the core/connector to be compliant, as long as the client interface responds appropriately. To be compliant as a Jangle core, however, it must be able to communicate with at least one connector.
The only HTTP methods covered by this specification are GET and HEAD. Future revisions will define how the other methods are handled.
All Jangle applications must respond with an Atom Services document at base_url/services/ (or be redirected to one) and return the content-type application/atomsvc+xml. This is the only reserved path for Jangle core compliant applications.
Typically, Jangle applications proxy a connector off of a subdirectory off of the base_url.
Example:
http://demo.jangle.org/openbiblio/
Where http://demo.jangle.org/ is the base url and an openbiblio is the path to the connector.
Jangle core communicates to connectors via HTTP. The connector responses are JSON objects.
Jangle core should submit all incoming HTTP header information to the connector (excluding accept headers). The content-type that Jangle core should request from the connector is application/json. The core is expected to also send an additional header, X-Connector-Base which is set to the URI of the Jangle core host and the path to the connector.
Example of X-Connector-Base header:
X-Connector-Base: http://demo.jangle.org/openbiblio/
Without this header, a Jangle connector cannot construct appropriate URIs, especially within the resource data.
The core should return the HTTP status codes verbatim from the connector.
Connector entity paths do not have to conform to the Jangle entity names. The paths to entities must be declared in the connector services response, however all public Jangle URIs must conform to the Jangle entity URI structure.
All Jangle implementations must return an Atom Services document from the base_url/services/ URL.
Example:
http://demo.jangle.org/services/
Methods allowed: GET, HEAD
Content-type required: application/atomsvc+xml
The schema and syntax of the service document is identical to how it is defined in RFC 5023.
Here is how Jangle uses the Atom Service elements:
An example service document:
<?xml version="1.0" encoding="UTF-8"?>
<service xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
<workspace>
<atom:title>openbiblio</atom:title>
<collection href="http://demo.jangle.org/openbiblio/items">
<atom:title>Holdings records</atom:title>
</collection>
<collection href="http://demo.jangle.org/openbiblio/actors">
<atom:title>Borrowers</atom:title>
</collection>
<collection href="http://demo.jangle.org/openbiblio/collections">
<atom:title>Categories</atom:title>
</collection>
<collection href="http://demo.jangle.org/openbiblio/resources">
<atom:title>Bibliographic records</atom:title>
<categories fixed="no">
<atom:category
scheme="http://jangle.org/vocab/terms#dlf-ilsdi-resource"
term="opac" />
</categories>
</collection>
</workspace>
<workspace>
<atom:title>prism</atom:title>
<collection href="http://demo.jangle.org/prism/actors">
<atom:title>Borrowers</atom:title>
</collection>
<collection href="http://demo.jangle.org/prism/collections">
<atom:title>Categories</atom:title>
</collection>
<collection href="http://demo.jangle.org/prism/resources">
<atom:title>Bibliographic records</atom:title>
</collection>
</workspace>
</service>
Here is how the connector JSON elements should be applied to the Atom Service document.
The "type" element being set to "services" tells the Jangle core that it should serialize the response into an Atom Service document.
Feed documents are main document types used in Jangle. They are Atom Syndication Format documents and carry the resource data in the atom:entry/content element. Feed elements are used for both collections of resources and single resources.
Example:
http://demo.jangle.org/openbiblio/actors/
Methods allowed: GET, HEAD
Content-type required: application/atom+xml
The schema and syntax of the Atom Feed is structurally identical to how it is defined in RFC 4287, although Jangle defines two extension attributes that appear in <link> elements: jangle:format and jangle:relationship.
Since each entity could span many thousands to millions of resources, Jangle uses feed paging as defined in RFC 5005. The way paged feeds are retrieved and how many resources are contained in given feed is left to the discretion of the implementer.
As a general rule, Jangle feeds that contain more than one resource should be sorted descending by last modification date. Feeds of lists or ranges of resources have no set expectation on the order of resources contained.
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:jangle="http://jangle.org/vocab/">
<title>openbiblio</title>
<link href="http://demo.jangle.org/openbiblio/resources/"/>
<updated>2008-10-02T14:39:37Z</updated>
<link rel="first" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/?offset=0"/>
<link rel="last" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/?offset=6000"/>
<link rel="next" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/?offset=100"/>
<link rel="self" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/" jangle:format="http://jangle.org/vocab/formats#http://www.loc.gov/MARC21/slim"/>
<link rel="http://jangle.org/vocab/formats#http://purl.org/dc/elements/1.1/" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/?format=dc"/>
<link rel="http://jangle.org/vocab/formats#application/marc" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/?format=marc"/>
<link rel="http://jangle.org/vocab/formats#http://www.openarchives.org/OAI/2.0/oai_dc/" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/?format=oai_dc"/>
<link rel="http://jangle.org/vocab/formats#http://www.loc.gov/mods/v3" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/?format=mods"/>
<link rel="search"
href="http://demo.jangle.org/openbiblio/resources/search/description/"
type="application/opensearchdescription+xml" />
<id>http://demo.jangle.org/openbiblio/resources/</id>
<entry>
<title>The Untamed</title>
<link href="http://demo.jangle.org/openbiblio/resources/5878" jangle:format="http://jangle.org/vocab/formats#http://www.loc.gov/MARC21/slim"/>
<link rel="related" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/5878/collections/" jangle:relationship="http://jangle.org/vocab/Entity#Collection"/>
<link rel="alternate" type="text/html" href="http://catalog.jangle.org/openbiblio/shared/biblio_view.php?bibid=5878&tab=opac"/>
<link rel="http://jangle.org/vocab/formats#http://purl.org/dc/elements/1.1/" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/5878?format=dc"/>
<link rel="http://jangle.org/vocab/formats#application/marc" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/5878?format=marc"/>
<link rel="http://jangle.org/vocab/formats#http://www.openarchives.org/OAI/2.0/oai_dc/" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/5878?format=oai_dc"/>
<link rel="http://jangle.org/vocab/formats#http://www.loc.gov/mods/v3" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/5878?format=mods"/>
<author>
<name>Brand, Max,</name>
</author>
<id>http://demo.jangle.org/openbiblio/resources/5878</id>
<updated>2008-03-18T15:57:00-04:00</updated>
<content type="application/xml">
<record xmlns='http://www.loc.gov/MARC21/slim'><leader> Z 22 4500</leader><datafield tag='245' ind1='0' ind2='0'><subfield code='a'>The Untamed</subfield><subfield code='b'></subfield><subfield code='c'>by Max Brand</subfield></datafield><datafield tag='100' ind1='0' ind2='z'><subfield code='a'>Brand, Max,</subfield></datafield><datafield tag='42' ind1='z' ind2='z'><subfield code='a'>dc</subfield></datafield><datafield tag='100' ind1='z' ind2='z'><subfield code='d'>1892-1944</subfield></datafield><datafield tag='245' ind1='z' ind2='z'><subfield code='h'>[electronic resource] /</subfield></datafield><datafield tag='260' ind1='z' ind2='z'><subfield code='b'>Project Gutenberg,</subfield><subfield code='c'>2004</subfield></datafield><datafield tag='500' ind1='z' ind2='z'><subfield code='a'>Project Gutenberg</subfield></datafield><datafield tag='506' ind1='z' ind2='z'><subfield code='a'>Freely available.</subfield></datafield><datafield tag='516' ind1='z' ind2='z'><subfield code='a'>Electronic text</subfield></datafield><datafield tag='830' ind1='z' ind2='z'><subfield code='a'>Project Gutenberg</subfield><subfield code='v'>10886</subfield></datafield><datafield tag='856' ind1='z' ind2='z'><subfield code='u'>http://www.gutenberg.org/etext/10886</subfield><subfield code='3'>Rights</subfield></datafield><datafield tag='856' ind1='z' ind2='z'><subfield code='u'>http://www.gutenberg.org/license</subfield></datafield></record> </content>
<category term="opac"/>
</entry>
...
</feed>
Jangle has defined special atom link "rel" attribute values to define alternate data formats available for the resources in a given feed and the related resources to any given atom:entry.
To declare a feed for the same set of resources (or resource) using a different record format (in this case, Dublin Core rather than marcxml), the following syntax is used:
<link rel="http://jangle.org/vocab/formats#http://purl.org/dc/elements/1.1/" type="application/atom+xml" href="http://demo.jangle.org/openbiblio/resources/5878?format=dc"/>
The rel attribute uses a URI that unambiguously declares the format that would be delivered in the linked feed. The URI http://jangle.org/vocab/formats# must be present to use this link syntax. The remaining URI fragment (in this case, http://purl.org/dc/elements/1.1/) is an identifier to denote the data format present. It does not have to be a namespace URI (any string will do). The full URI (http://jangle.org/vocab/formats#http://purl.org/dc/elements/1.1/) should be dereferenceable to a definition of the identifier. It is within the scope of the Jangle initiative to provide this vocabulary (and a means to contribute to it).
The type attribute must be application/atom+xml. The href attribute should be the URI to the feed which contains the alternate data format. The URI pattern is left to the discretion of the implementer.
These link elements may appear as child elements of the <feed> element or an <entry> element.
Jangle feeds also define relationships between resources. If an Actor has multiple Items associated with it (for example, a borrower has several items checked out), that relationship can be declared like this:
<link type="application/atom+xml" href="http://demo.jangle.org/openbiblio/actors/1711/items/" rel="related" jangle:relationship="http://jangle.org/vocab/Entity#Item"/>
Jangle defined an extension attribute, jangle:relationship to provide the connection between two (or more) resources.
In order to explicitly identify the format of the entity content element payload, Jangle has defined another extension attribute: jangle:format. For feeds with homogeneous record formats (i.e. all entries use the same format), this extension should appear on the rel="self" link element at the feed level and on a link element in the entry. If the record formats are heterogeneous within the feed, the attribute need only appear on link elements within the entry elements. The value of the attribute should be a Jangle format URI (such as: http://jangle.org/vocab/formats#application/marc).
If an entity is flagged as searchable in the connector services response, the Jangle core should also provide an OpenSearch autodiscovery link:
<link rel="search"
href="http://demo.jangle.org/openbiblio/resources/search/description/"
type="application/opensearchdescription+xml" />
Which would actually return a Jangle Explain document.
Here is how the connector JSON elements should be applied to the Atom Syndication Format document.
The "type" element being set to "feed" tells the Jangle core that it should serialize the response into an Atom Syndication Format document.
See an example feed for a point of reference.
To build the <link> elements, it is probably easiest to look at this from the opposite direction.
The link elements would be built from the "alternate_formats", ["data"][i]["alternate_formats"], ["data"][i]["relationships"], "links", ["data"][i]["links"] elements.
From the "alternate_formats" and ["data"][i]["alternate_formats"] elements, the <link> element's attributes would come from:
The ["data"][i]["relationships"] are used the following way:
The <link> tags created from the "link" elements is pretty straightforward. The "rel" attribute value is set from the hash key ("alternate", "relation", etc.). The remaining object properties should be set as the element attributes ("href", "type", "title", etc.).
Jangle connector feed or search responses can include URLs to XSLT stylesheets to be applied at either the "feed" level or the "entry/content" level. Jangle does not define which version of XSLT is permissible, but developers should not assume all Jangle core implementations can support XSLT 2.0.
The stylesheet URLs must be accessible to the Jangle core via HTTP.
"Feed" level stylesheets (which is sent in JSON as an array) are to be applied after the connector response has been serialized as an Atom Syndication Format feed. The stylesheets are applied serially, in the order they appear in the array.
Resource level stylesheets can be applied at any time, since they should transform the data in the atom:entry/content tag as an independent document, not as a child element in the Atom feed.
The stylesheets should not transform the Atom into another format, although they can be used to set the values of the Atom elements or provide Atom extensions.
Searching in Jangle is provided through OpenSearch. The query syntax uses CQL to define search indexes.
Jangle extends the OpenSearch Description document to include elements of the SRU explain document schema.
Search results use a similar Atom document to the feed results, but include the OpenSearch extensions.
The description document advertises how to search resources for clients.
Example:
http://demo.jangle.org/openbiblio/resources/search/description/
Methods allowed: GET, HEAD
Content-type required: application/opensearchdescription+xml
Jangle extends the standard OpenSearch Description document with elements from the SRU Explain schema. This allows clients to know which indexes are available to search on in the query element.
Example Jangle Search Description Document.
<?xml version="1.0" encoding="utf-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:jangle="http://jangle.org/opensearch/">
<ShortName>Bibliographic records</ShortName>
<LongName>Search Bibliographic records in OpenBiblio</LongName>
<Description>Bibliographic records search. Defaults to keyword anywhere.</Description>
<Tags>catalog library</Tags>
<SyndicationRight>open</SyndicationRight>
<Url type="application/atom+xml" template="http://demo.jangle.org/openbiblio/resources/search/?offset={startIndex?}&count={count?}&query={searchTerms?}&format={jangle:format?}"/>
<Query role="example" searchTerms="dc.creator=thomas">
<zr:explain xmlns:zr="http://explain.z3950.org/dtd/2.1/">
<zr:indexInfo>
<zr:set name="dc" identifier="info:srw/cql-context-set/1/dc-v1.1"/>
<zr:set name="rec" identifier="info:srw/cql-context-set/2/rec-1.1"/>
<zr:set name="cql" identifier="info:srw/cql-context-set/1/cql-v1.2"/>
<zr:index>
<zr:map><zr:name set="dc">title</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="dc">creator</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="dc">subject</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="dc">publisher</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="dc">format</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="dc">identifier</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="rec">identifier</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="rec">collectionName</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="rec">lastModificationDate</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="rec">creationDate</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="cql">allRecords</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="cql">allIndexes</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="cql">anyIndexes</zr:name></zr:map>
</zr:index>
<zr:index>
<zr:map><zr:name set="cql">keywords</zr:name></zr:map>
</zr:index>
</zr:indexInfo>
</zr:explain>
<Query>
</OpenSearchDescription>
The "explain" data becomes a child element of the OpenSearch:Query element.
Jangle search results are mostly identical to standard Entity feeds with the notable addition of the OpenSearch extension.
Search feeds can be identified from the Jangle connector by the "type" property being set to "search".
In addition to the mapping of the JSON properties to the feed document, the following properties should be mapped to OpenSearch elements:
The <opensearch:itemsPerPage> element can be set to the number of objects in the "data" array. Note: there is an assumption that Jangle feeds provide a consistent number of resources per page. As a result, provisions may need to be made for the last page in a result set in the event that the number of resources in the feed is less than the normal page default.
The search query terms (which should be a CQL query string) should be used to make the OpenSearch Query element:
<opensearch:Query role="request" searchTerms="{cql_query_string}" startIndex="0" />
Since feed offsets start with "0", search startIndex attributes should also be set to "0".
Search results feeds must include the OpenSearch namespace declaration: http://a9.com/-/spec/opensearch/1.1/