<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Programming on Crossref</title><link>https://www-crossref-org.pluma.sjfc.edu/categories/programming/</link><description>Recent content in Programming on Crossref</description><generator>Hugo 0.139.4</generator><language>en-us</language><managingEditor>support@crossref.org (Crossref/Cazinc/Benoît Benedetti)</managingEditor><webMaster>support@crossref.org (Crossref/Cazinc/Benoît Benedetti)</webMaster><lastBuildDate>Tue, 24 Apr 2018 00:00:00 +0000</lastBuildDate><atom:link href="https://www-crossref-org.pluma.sjfc.edu/categories/programming/" rel="self" type="application/rss+xml"/><item><title>Redirecting redirection</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/redirecting-redirection/</link><pubDate>Tue, 24 Apr 2018 00:00:00 +0000</pubDate><author>Geoffrey Bilder</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/redirecting-redirection/</guid><description>&lt;p>Crossref has decided to change the HTTP redirect code used by our DOIs from &lt;code>303&lt;/code> back to the more commonly used &lt;code>302&lt;/code>. Our implementation of 303 redirects back in 2010 was based on recommended best practice for supporting linked data identifiers. Unfortunately, very few other parties have adopted this practice.&lt;/p>
&lt;p>What’s more, because using a 303 redirect is still unusual, it tends to throw &lt;a href="https://en.wikipedia.org/wiki/Search_engine_optimization" target="_blank">SEO&lt;/a> tools into a &lt;a href="http://www.dictionary.com/browse/tizzy?s=t" target="_blank">tizzy&lt;/a>- and we spend a lot of time fielding SEO questions from our members about our use of 303s.&lt;/p>
&lt;h2 id="a-nametldratldra">&lt;a name="tldr">&lt;/a>TL;DR&lt;/a>&lt;/h2>
&lt;p>At this point, we need to emphasise that we have never seen our use of 303s actually affect page rankings. But at the same time, use of 303 redirects has not had wider uptake. Maintaining this quixotic behaviour just isn’t worth the effort. We hope that, in the future, we can use other techniques (e.g. &lt;a href="https://signposting.org/" target="_blank">signposting&lt;/a> &amp;amp; &lt;a href="https://datatracker.ietf.org/doc/draft-vandesompel-citeas/" target="_blank">cite-as&lt;/a>) to achieve some of the things that 303 was supposed to do.&lt;/p>
&lt;p>Note that these changes &lt;strong>will not affect users or machines using DOIs&lt;/strong>. The change should be entirely transparent.&lt;/p>
&lt;p>Below we provide some background to our decision and after that we provide some detailed technical notes from &lt;a href="https://orcid.org/0000-0001-7694-8250" target="_blank">Jonathan Rees&lt;/a> and &lt;a href="https://orcid.org/0000-0001-5490-1347" target="_blank">Henry Thompson&lt;/a> who have been very kind in helping to provide Crossref technical guidance on how we can help DOIs best support linked open data and adhere to HTTP best practice.&lt;/p>
&lt;h2 id="a-namebackgroundbackgrounda">&lt;a name="background">Background&lt;/a>&lt;/h2>
&lt;p>Back in 2010, Crossref, DataCite (and later, several other RAs) responded to &lt;a href="https://doi-org.pluma.sjfc.edu/10.64000/x2spb-3d247" target="_blank">concerns that DOIs were not &amp;ldquo;linked-data friendly.&amp;rdquo;&lt;/a> There were three problems with DOIs at that time:&lt;/p>
&lt;ol>
&lt;li>It was not clear that DOIs could be used and expressed as HTTP URIs.&lt;/li>
&lt;li>There was no standard way to ask a DOI to return a machine-readable representation of the data.&lt;/li>
&lt;li>It wasn’t always clear if the DOI resolved to &amp;ldquo;the thing&amp;rdquo; (e.g. an article) or “something about the thing” (e.g. a landing page).&lt;/li>
&lt;/ol>
&lt;p>On the advice of several people in the linked data community, &lt;a href="https://doi-org.pluma.sjfc.edu/10.64000/8f0n4-64m15" target="_blank">we proposed some options for fixing this&lt;/a>. And we finally settled on:&lt;/p>
&lt;ol>
&lt;li>Recommending that Crossref DOIs be expressed and displayed as HTTP (&lt;a href="https://doi-org.pluma.sjfc.edu/10.13003/5jchdy" target="_blank">now HTTPS&lt;/a>) URIs. This made it clear that DOIs could be used with HTTP applications.&lt;/li>
&lt;li>Enabling DOI registration agencies to support content negotiation. This allowed RAs to support providing machine-readable representations of the data associated with a DOI.&lt;/li>
&lt;li>Changing the underlying redirect code from the normal 302 to 303. This was designed to clarify what, at the time, was true- that most DOIs resolved to a landing page, not the article itself.&lt;/li>
&lt;/ol>
&lt;p>By any practical measure, machine use of DOIs has exploded since we made these decisions back in 2010. Crossref’s APIs and content negotiation handle over 800 million requests for machine readable data a month. Our sibling organisation, &lt;a href="https://www.datacite.org" target="_blank">DataCite&lt;/a>, has also seen a huge growth in machine use of DOIs. Many applications, from bibliographic management tools, to authoring systems and CRIS systems, make use of machine actionable DOIs all the time. So clearly our work to promote DOIs as machine actionable identifiers is working, but we are certain that our current use of 303 redirects has nothing to do with this growth.&lt;/p>
&lt;p>First of all, as we said, very few parties have actually subscribed to the notion of using 303s to help distinguish &amp;ldquo;the thing&amp;rdquo; from “something about the thing”.&lt;/p>
&lt;p>Secondly, even if they did try to rely on 303s to make this distinction, they would quickly get confused because the DOI is so often just the first in a chain of redirects which do not implement the same semantic distinction. At this point we should be clear - Crossref thinks these kinds of long redirect chains are a bad idea for two main reasons:&lt;/p>
&lt;ul>
&lt;li>They slow down resolution.&lt;/li>
&lt;li>They increase the number of potential failure points between the DOI and the item it resolves to.&lt;/li>
&lt;/ul>
&lt;p>But we also cannot legislate them away. They exist. And in the real world you will find plenty of DOIs that do a 303 redirect to a system that, in turn, does a 302 redirect to a system that does a 301 redirect and…eventually ends up someplace returning a 200. You get the picture. How on earth is a machine supposed to interpret a 303-&amp;gt;302-&amp;gt;301-&amp;gt;302 redirect chain?&lt;/p>
&lt;p>Furthermore - nowadays, after following this chain of redirects, you will often find yourself on a &amp;ldquo;page&amp;rdquo; that is &lt;em>both&lt;/em> a landing page &lt;em>and&lt;/em> the article itself. Dynamic, one-page applications can simply morph the one into the other without the use of additional HTTP requests.&lt;/p>
&lt;p>In other words, using 303s is not helping machines interpret what the DOI is pointing at. And yet, people seem to be making good use of machine actionable DOIs and they are not complaining much about it.&lt;/p>
&lt;p>Personally, I’d might have just been happy to switch back to using 302s &lt;em>simply&lt;/em> so that I could cut down on my conversations with SEO hacks. But that wouldn’t be a principled approach. In 2010 we spent a lot of time considering the initial switch to 303s- we needed to consult with the LOD community on a potential switch back to 302s. At the January 2018 &lt;a href="https://pidapalooza.org/" target="_blank">PIDapalooza&lt;/a> I had a chance to talk to Henry Thomson about the 302/303 dilemma we faced, and he along with Jonathan Rees very generously provided the following feedback.&lt;/p>
&lt;h2 id="a-namedetailsbest-practices-for-http-redirection-by-persistent-identifier-resolvers-302-vs-303a">&lt;a name="details">Best practices for HTTP redirection by persistent identifier resolvers: 302 vs. 303&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>Jonathan Rees (MIT CSAIL, &lt;a href="https://orcid.org/0000-0001-7694-8250" target="_blank">https://orcid.org/0000-0001-7694-8250&lt;/a>)&lt;/li>
&lt;li>Henry Thompson (University of Edinburgh, School of Informatics, &lt;a href="https://orcid.org/0000-0001-5490-1347" target="_blank">https://orcid.org/0000-0001-5490-1347&lt;/a>)&lt;/li>
&lt;/ul>
&lt;p>If one goes to the trouble to organize an identifier system, then the desire that such a system should last as long as possible leads one to aspirationally say it’s a &lt;em>persistent&lt;/em> identifier (PID) system. The unwillingness of the major browser suppliers to implement new URI schemes for PIDs initially hindered their use on the Web and this in turn inhibited widespread adoption. More recently a number of PID approaches have enjoyed very rapid growth as a result of a compromise: these PIDs participate in the World Wide Web by defining simple conversion rules mapping identifiers to &lt;em>actionable&lt;/em> (&amp;lsquo;http:&amp;rsquo; and/or &amp;lsquo;https:&amp;rsquo;) forms and providing resolution servers that redirect requests for such forms to the appropriate destination.This approach has been widely adopted and is very successful, because it is so useful. An identifier’s actionable form leads, via the HTTP protocol and one or more redirections, to a web page that bears on the ground identity of the associated entity – or perhaps even directly to the entity itself, if the system is one for document entities that are naturally provided as web pages. The nature of the retrieved web page varies from one system to the next.&lt;/p>
&lt;p>A confusion arose, however, over claims in various technical specifications (&lt;a href="https://tools.ietf.org/html/rfc3986" target="_blank">URIs&lt;/a>, &lt;a href="https://tools.ietf.org/html/rfc2616" target="_blank">HTTP&lt;/a>, &lt;a href="https://www.w3.org/TR/webarch/" target="_blank">Web Architecture&lt;/a>) that the normal case is for the protocol to yield a &amp;ldquo;representation&amp;rdquo; of the “resource” “identified” by the URI. None of these terms is adequately defined by the specifications, and initially the language was not taken as normative. Those deploying identifier systems took the HTTP “resource” to be the entity associated with an identifier, and understood the “resource” as being “identified” by the URI, but it was never clear what was, or wasn’t, a “representation” of a given entity/resource: a description of the resource, the resource itself, a version of the resource, instructions on how to find the resource, etc. Sixteen years ago, in an attempt to clarify the intent of this part of the theory of URIs, and to allow applications to usefully and uniformly exploit the idea that an HTTP 200 response must deliver a “representation” of the “resource”, Tim Berners-Lee &lt;a href="https://lists.w3.org/Archives/Public/www-tag/2002Mar/0092" target="_blank">asked&lt;/a> the &lt;a href="https://www.w3.org/2001/tag/" target="_blank">W3C Technical Architecture Group&lt;/a> to consider what came to be known as the &lt;a href="https://www.w3.org/2001/tag/group/track/issues/14" target="_blank">httpRange-14&lt;/a> issue. It’s now 13 years after the TAG gave &lt;a href="https://lists.w3.org/Archives/Public/www-tag/2005Jun/0039.html" target="_blank">advice&lt;/a> which almost no one was happy with, and 5 years after work on issue &lt;a href="https://www.w3.org/2001/tag/group/track/issues/57" target="_blank">httpRedirections-57&lt;/a> (which superseded httpRange-14) ground to a halt. There’s still no consensus on whether it’s OK to return landing pages with a 200 status in response to requests for pictures or publications, but the Web seems to be working nonetheless, and no one seems to be bothered much anymore.&lt;/p>
&lt;p>The provision of HTTP-based resolution services has stimulated widespread support for the use of identifier systems with Web resolution, particularly in the scholarly journal publication context. Those setting up HTTP resolvers responsible for identifier systems must decide which HTTP response code should be used. The TAG’s advice sows doubt on the use of the 200 response code when the response would have been a landing page, and many resolvers avoid 200 regardless and use redirection for administrative purposes, for example&lt;/p>
&lt;p>‘&lt;a href="https://dx-doi-org.pluma.sjfc.edu/10.1109/5.771073" target="_blank">https://dx-doi-org.pluma.sjfc.edu/10.1109/5.771073&lt;/a>’ to&lt;/p>
&lt;p>‘&lt;a href="http://ieeexplore.ieee.org/document/771073/?reload=true" target="_blank">http://ieeexplore.ieee.org/document/771073/?reload=true&lt;/a>’ for the DOI&lt;/p>
&lt;p>‘10.1109/5.771073’, or ‘&lt;a href="https://identifiers.org/uniprot/A0A022YWF9" target="_blank">https://identifiers.org/uniprot/A0A022YWF9&lt;/a>’ to&lt;/p>
&lt;p>‘&lt;a href="http://www.uniprot.org/uniprot/A0A022YWF9" target="_blank">http://www.uniprot.org/uniprot/A0A022YWF9&lt;/a>’ for the Uniprot identifier&lt;/p>
&lt;p>‘A0A022YWF9’.&lt;/p>
&lt;p>So the response should be a redirection, but what kind, 301, 302, or 303? (Or 307, which is almost the same as 302.) A 301 redirect seems to say that the URI is not persistent (since its target is deemed &amp;ldquo;more persistent&amp;rdquo;). A 302 redirect seems to say that the response could have come via a 200, and so suffers the same fate as 200. That leaves 303, as hinted at in the TAG’s advice. This idea got some traction: Ten years ago a Semantic Web interest group promoted the TAG’s advice in &lt;a href="https://www.w3.org/TR/cooluris/" target="_blank">a published note&lt;/a>, and seven years ago one of us wrote a &lt;a href="https://odontomachus.wordpress.com/2011/05/04/crossrefs-gift-of-metadata/" target="_blank">blog post&lt;/a> giving the same advice for resolvers for PIDs in publishing.&lt;/p>
&lt;p>However, not only is there neither consensus nor general utility around this strict understanding of the use of the various response codes – that is, that resolution to a landing page is inconsistent with a 200 (and &lt;em>a posteriori&lt;/em> therefore with a 302) – but also the range of usage patterns for redirection of HTTP requests has grown and ramified over time as the Web has grown and become more complex. It’s on the face of it unlikely that a mere three response codes can capture all the resulting complexity or cover the space of outcomes (in terms of e.g. what ends up in the browser address bar or what search engines index a page under) that a page owner might like to signal.&lt;/p>
&lt;p>We find in practice that some PID redirections &lt;em>are&lt;/em> ending up (usually after further publisher-local redirects) at the &amp;ldquo;identified&amp;rdquo; document, some at landing pages, and some at one &lt;em>or&lt;/em> the other depending on the requesting site, for example in the case of paywalled material.&lt;/p>
&lt;p>In the absence of a rethinking of the whole 3xx space, it seems to us that only the 301 vs. 302 distinct ion (roughly, 301 = permanent = please fix the link, and 302 = temporary = don’t change the link) is well understood and more or less consistently treated, whereas for 303, web servers are not very consistent and both &lt;a href="http://sharkseo.com/nohat/303-redirects-seo/" target="_blank">search engine&lt;/a> and citation crawler behaviours are at best inconsistent and at worst downright unhelpful.&lt;/p>
&lt;p>So, we believe it is in both users’ and publishers’ interests for resolvers of actionable-form PIDs to use 302 redirects, not 303.&lt;/p>
&lt;p>If we want to help machines better understand the resource that a DOI points at, we have to explore using more nuanced mechanisms.&lt;/p>
&lt;p>Just using 302 for the first redirect doesn&amp;rsquo;t do everything necessary to effectively support the emerging PID+redirection architecture. It&amp;rsquo;s at the &lt;em>end&lt;/em> of the redirect chains that we need more: a standardised way to find the PID back at the start of the chain. The &lt;a href="https://datatracker.ietf.org/doc/draft-vandesompel-citeas/" target="_blank">&amp;lsquo;cite-as&amp;rsquo; proposal&lt;/a> does exactly this, and we hope it&amp;rsquo;s quickly approved and widely adopted. Once &lt;em>that&lt;/em> happens a proposal for augmenting browser (and API) behaviour to prefer, or at least offer, the &amp;lsquo;cite-as&amp;rsquo; link for bookmarking and copying will be needed.&lt;/p></description></item><item><title>Using AWS S3 as a large key-value store for Chronograph</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/using-aws-s3-as-a-large-key-value-store-for-chronograph/</link><pubDate>Tue, 02 Aug 2016 00:00:00 +0000</pubDate><author>Joe Wass</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/using-aws-s3-as-a-large-key-value-store-for-chronograph/</guid><description>&lt;p>&lt;span >One of the cool things about working in Crossref Labs is that interesting experiments come up from time to time. One experiment, entitled “what happens if you plot DOI referral domains on a chart?” turned into the &lt;a href="http://chronograph.labs.crossref.org.pluma.sjfc.edu">Chronograph&lt;/a> project. In case you missed it, Chronograph analyses our DOI resolution logs and shows how many times each DOI link was resolved per month, and also how many times a given domain referred traffic to DOI links per day.&lt;/span>&lt;/p>
&lt;p>&lt;span >We’ve released a new version of Chronograph. This post explains how it was put together. One for the programmers out there.&lt;/span>&lt;/p>
&lt;h2 id="span-big-enough-to-be-annoyingspan">&lt;span >Big enough to be annoying&lt;/span>&lt;/h2>
&lt;p>&lt;span >Chronograph sits on the boundary between normal-sized data and large-enough-to-be-annoying-size data. It doesn’t store data for all DOIs (it includes only those that are used on average once a day), but it has information on up to 1 million DOIs per month over about 5 years, and about 500 million data points in total.&lt;/span>&lt;/p>
&lt;p>&lt;span >Storing 500 million data points is within the capabilities of a well-configured database. In the first iteration of Chronograph a MySQL database was used. But that kind of data starts to get tricky to back up, move around and index.&lt;/span>&lt;/p>
&lt;p>&lt;span >Every month or two new data comes in for processing, and it needs to be uploaded and merged into the database. Indexes need to be updated. Disk space needs to be monitored. This can be tedious.&lt;/span>&lt;/p>
&lt;h2 id="span-key-valuesspan">&lt;span >Key values&lt;/span>&lt;/h2>
&lt;p>&lt;span >Because the data for a DOI is all retrieved at once, it can be stored together. So instead of a table that looks like&lt;/span>&lt;/p>
&lt;table>
&lt;tr>
&lt;td>
&lt;span >10.5555/12345678&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;2010-01-01&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;5&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >10.5555/12345678&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;2010-02-01&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;7&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >10.5555/12345678&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;2010-03-01&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;3&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;/table>
&lt;p>&lt;span >Instead we can store&lt;/span>&lt;/p>
&lt;table>
&lt;tr>
&lt;td>
10.5555/12345678
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
{&amp;amp;#8220;2010-01-01&amp;amp;#8221;: 5, &amp;amp;#8220;2010-02-01&amp;amp;#8221;: 7, &amp;amp;#8220;2010-03-01&amp;amp;#8221;: 3}
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;/table>
&lt;p>&lt;span >This is much lighter on the indexes and takes much less space to store. However, it means that adding new data is expensive. Every time there’s new data for a month, the structure must be parsed, merged with the new data, serialised and stored again millions of times over.&lt;/span>&lt;/p>
&lt;p>&lt;span >After trials with &lt;a href="https://www.mysql.com/">MySql&lt;/a>, &lt;a href="https://www.mongodb.com/">MongoDB&lt;/a> and &lt;a href="http://www.mapdb.org/">MapDB&lt;/a>, this approach was taken with MySQL in the original Chronograph.&lt;/span>&lt;/p>
&lt;h2 id="span-keep-it-simple-storage-service-stupidspan">&lt;span >Keep it Simple Storage Service Stupid&lt;/span>&lt;/h2>
&lt;p>&lt;span >In the original version of Chronograph the data was processed using &lt;a href="http://spark.apache.org/">Apache Spark&lt;/a>. There are various solutions for storing this kind of data, including Cassandra, time-series databases and so on.&lt;/span>&lt;/p>
&lt;p>&lt;span >The flip side of being able to do interesting experiments is wanting them to stick around without having to bother a sysadmin. The data is important to us, but we’d rather not have to worry about running another server and database if possible.&lt;/span>&lt;/p>
&lt;p>&lt;span >Chronograph fits into the category of ‘interesting’ rather than ‘mission-critical’ projects, so we’d rather not have to maintain expensive infrastructure if possible.&lt;/span>&lt;/p>
&lt;p>&lt;span >I decided to look into using Amazon Web Services &lt;a href="https://aws.amazon.com/s3/">Simple Storage Service&lt;/a> (AWS S3) to store the data. AWS itself is a key-value store, so it seems like a good fit. S3 is a great service because, as the name suggests, it’s a simple service for storing a large number of files. It’s cheap and its capabilities and cost scale well.&lt;/span>&lt;/p>
&lt;p>&lt;span >However, storing and updating up to 80 million very small keys (one per DOI) isn’t very clever, and certainly isn’t practical. I looked at &lt;a href="https://aws.amazon.com/documentation/dynamodb/">DynamoDB&lt;/a>, but we still face the overhead of making a large number of small updates.&lt;/span>&lt;/p>
&lt;h2 id="span-is-it-weirdspan">&lt;span >Is it weird?&lt;/span>&lt;/h2>
&lt;p>&lt;span >In these days of plentiful databases with cheap indexes (and by ‘these days’ I mean the 1970s onward) it seems somehow wrong to use plain old text files. However, the whole Hadoop “Big Data” movement was predicated on a return to batch processing files. Commoditisation of services like S3 and the shift to do more in the browser have precipitated a bit of a rethink. The movement to abandon LAMP stacks and use static site generators is picking up pace. The term ‘serverless architecture’ is hard to avoid if you read &lt;a href="https://hn.algolia.com/?query=serverless%20architecture&amp;sort=byDate&amp;prefix&amp;page=0&amp;dateRange=all&amp;type=story">certain news sites&lt;/a>.&lt;/span>&lt;/p>
&lt;p>&lt;span >Using Apache Spark (with its brilliant &lt;a href="http://spark.apache.org/docs/latest/programming-guide.html#resilient-distributed-datasets-rdds">RDD concept&lt;/a>) was useful for bootstrapping the data processing for Chronograph, but the new code has an entirely flat-file workflow. The simplicity of not having to unnecessarily maintain a &lt;a href="https://hadoop.apache.org/docs/r1.2.1/hdfs_design.html">Hadoop HDFS&lt;/a> instance seems to be the right choice in this case.&lt;/span>&lt;/p>
&lt;h2 id="span-repurposing-the-wheelspan">&lt;span >Repurposing the Wheel&lt;/span>&lt;/h2>
&lt;p>&lt;span >The solution was to use S3 as a big &lt;a href="https://en.wikipedia.org/wiki/Hash_table">hash table&lt;/a> to store the final data that’s served to users.&lt;/span>&lt;/p>
&lt;p>&lt;span >The processing pipeline uses flat files all the way through from input log files to projections to aggregations. At the penultimate stage of the pipeline blocks of CSV per DOI are produced that represent date-value pairs.&lt;/span>&lt;/p>
&lt;table>
&lt;tr>
&lt;td>
10.5555/12345678
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
2010-01
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
2010-01-01,05&amp;lt;br /&amp;gt; 2010-02-01,02&amp;lt;br /&amp;gt; 2010-01-03,08&amp;lt;br /&amp;gt; &amp;amp;#8230;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
10.5555/12345678
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
2010-02
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
2010-02-1,10&amp;lt;br /&amp;gt; 2010-02-01,7&amp;lt;br /&amp;gt; 2010-02-03,22&amp;lt;br /&amp;gt; &amp;amp;#8230;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;/table>
&lt;p>&lt;span >At the last stage, these are combined into blocks of all dates for a DOI&lt;/span>&lt;/p>
&lt;table>
&lt;tr>
&lt;td>
10.5555/12345678
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
2010-01
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
2010-01-01,05&amp;lt;br /&amp;gt; 2010-02-01,02&amp;lt;br /&amp;gt; 2010-01-03,08&amp;lt;br /&amp;gt; &amp;amp;#8230;&amp;lt;br /&amp;gt; 2010-02-1,10&amp;lt;br /&amp;gt; 2010-02-01,7&amp;lt;br /&amp;gt; 2010-02-03,22&amp;lt;br /&amp;gt; &amp;amp;#8230;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;/table>
&lt;p>&lt;span >The DOIs are then hashed into 12 bits and stored as chunks of CSV&lt;/span>&lt;/p>
&lt;p>&lt;span >day-doi.csv-chunks_8841:&lt;/span>&lt;/p>
&lt;pre class="">10.1038/ng.3020
2014-06-24,4
2014-06-25,4
2014-06-26,3
...
10.1007/978-94-007-2869-1_7
2012-06-01,12
2012-06-02,8
...
10.1371/journal.pone.0145509
2016-02-01,13
2016-02-02,75
2016-02-03,30
...&lt;/pre>
&lt;p>&lt;span >There are 65,536 (0x000 to 0xFFFF) possible files, each with about a thousand DOIs worth of data in each.&lt;/span>&lt;/p>
&lt;p>&lt;span >When the browser requests data for a DOI, it is hashed and then the request for the appropriate file in S3 is made. The browser then has to perform a linear scan of the file to find the DOI it is looking for.&lt;/span>&lt;/p>
&lt;p>&lt;span >This is the simplest possible form of hash table: simple addressing with separate &lt;a href="https://en.wikipedia.org/wiki/Hash_table#Separate_chaining_with_linked_lists">linear chaining&lt;/a>. The hash function is a 16-bit mask of MD5, chosen because of availability in the browser. It does a great job of evenly distributing the DOIs over all 65,536 possible files.&lt;/span>&lt;/p>
&lt;h2 id="span-striking-the-balancespan">&lt;span >Striking the balance&lt;/span>&lt;/h2>
&lt;p>&lt;span >In any data structure implementation, there are balances to be struck. Traditionally these concern memory layout, the shape of the data, practicalities of disk access and CPU cost.&lt;/span>&lt;/p>
&lt;p>&lt;span >In this instance, the factors in play included the number of buckets that need to be uploaded and the cost of the browser downloading an over-large bucket. The size of the bucket doesn’t matter much for CPU (as far as the user is concerned it takes about the same time to scan 10 entries as it does 10,000), but it does make a difference asking  user to download a 10kb bucket or a 10MB one.&lt;/span>&lt;/p>
&lt;p>&lt;span >I struck the balance at 4096 buckets, resulting in files of around 100k, which is the size of a medium sized image.&lt;/span>&lt;/p>
&lt;h2 id="span-it-worksspan">&lt;span >It works&lt;/span>&lt;/h2>
&lt;p>&lt;span >The result is a simple system that allows people to look up data for millions of DOIs, without having to look after another server. It’s also portable to any other file storage service.&lt;/span>&lt;/p>
&lt;p>&lt;span >The approach isn’t groundbreaking, but it works.&lt;/span>&lt;/p></description></item><item><title>Python and Ruby Libraries for accessing the Crossref API</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/python-and-ruby-libraries-for-accessing-the-crossref-api/</link><pubDate>Fri, 04 Mar 2016 00:00:00 +0000</pubDate><author>Scott Chamberlain</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/python-and-ruby-libraries-for-accessing-the-crossref-api/</guid><description>&lt;p>&lt;span >I’m a co-founder with &lt;a href="https://ropensci.org/">rOpenSci&lt;/a>, a non-profit that focuses on making software to facilitate reproducible and open science. &lt;a href="https://github.com/ropensci/rcrossref/commit/a264da3177d2bdbdfce289a4fdccc43c8df36da1">Back in 2013&lt;/a> we started to make an R client working with various Crossref web services. I was lucky enough to attend &lt;a href="https://www-crossref-org.pluma.sjfc.edu/crossref-annual-meeting/archive/">last year’s Crossref annual meeting in Boston&lt;/a>, and gave one talk on &lt;a href="https://youtu.be/_2iRjK5QjKU?si=qzAvJ70n_kaMJpmU">details of the programmatic clients&lt;/a>, and another higher level talk on &lt;a href="https://youtu.be/j8qlHw7UqlI?si=qWY4NXls4w4jwZ3I">text mining and use of metadata for research&lt;/a>.&lt;/span>&lt;/p>
&lt;p>&lt;span >Crossref has a newish API encompassing works, journals, members, funders and more (check out &lt;a href="https://github.com/Crossref/rest-api-doc/blob/master/rest_api.md">the API docs&lt;/a>), as well as a few other services. Essential to making the Crossref APIs easily accessible—and facilitating easy tool/app creation and exploration—are programmatic clients for popular languages. I’ve maintained an R client for a while now, and have been working on Python and Ruby clients for the past four months or so.&lt;/span>&lt;/p>
&lt;p>&lt;span >The R client falls squarely into the analytics/research use cases, while the Python and Ruby clients are ideal for general data access and use in web applications (the Javascript library below as well).&lt;/span>&lt;/p>
&lt;p>&lt;span >I’ve strived to make each client in idiomatic fashion according to the language. Due to this fact, there is not generally correspondence between the different clients with respect to data outputs. However, I’ve tried to make method names similar across Ruby and Python; although the R client is quite a bit older, so method names differ from the other clients and I’m resistant to changing them so as not to break current users’ projects. In addition, R users are likely to want a data.frame (i.e., table) of results, so we give back that - whereas with Python and Ruby we give back dictionaries and hashes, respectively.&lt;/span>&lt;/p>
&lt;h3 id="span-strongcrossref-clientsstrongspan">&lt;span >&lt;strong>Crossref clients&lt;/strong>&lt;/span>&lt;/h3>
&lt;ul>
&lt;li>&lt;span >Python:&lt;/span>
&lt;ul>
&lt;li>&lt;span >Source: &lt;a href="https://github.com/sckott/habanero">&lt;a href="https://github.com/sckott/habanero" target="_blank">https://github.com/sckott/habanero&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;li>&lt;span >Pypi: &lt;a href="https://pypi.python.org/pypi/habanero">&lt;a href="https://pypi.python.org/pypi/habanero" target="_blank">https://pypi.python.org/pypi/habanero&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;span >Ruby:&lt;/span>
&lt;ul>
&lt;li>&lt;span >Source: &lt;a href="https://github.com/sckott/serrano">&lt;a href="https://github.com/sckott/serrano" target="_blank">https://github.com/sckott/serrano&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;li>&lt;span >Rubygems: &lt;a href="https://rubygems.org/gems/serrano">&lt;a href="https://rubygems.org/gems/serrano" target="_blank">https://rubygems.org/gems/serrano&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;li>&lt;span >&lt;code>serrano&lt;/code> also comes with a command line tool of the same name that’s installed when you install &lt;code>serrano&lt;/code> (examples below)&lt;/span>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;span >R:&lt;/span>
&lt;ul>
&lt;li>&lt;span >Source: &lt;a href="https://github.com/ropensci/rcrossref">&lt;a href="https://github.com/ropensci/rcrossref" target="_blank">https://github.com/ropensci/rcrossref&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;li>&lt;span >CRAN: &lt;a href="https://cran.rstudio.com/web/packages/rcrossref/">&lt;a href="https://cran.rstudio.com/web/packages/rcrossref/" target="_blank">https://cran.rstudio.com/web/packages/rcrossref/&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;span >Javascript:&lt;/span>
&lt;ul>
&lt;li>&lt;span >Source: &lt;a href="https://github.com/scienceai/crossref">&lt;a href="https://github.com/scienceai/crossref" target="_blank">https://github.com/scienceai/crossref&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;li>&lt;span >NPM: &lt;a href="https://www.npmjs.com/package/crossref">&lt;a href="https://www.npmjs.com/package/crossref" target="_blank">https://www.npmjs.com/package/crossref&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>&lt;span >I’ll cover the Python, Ruby, and R libraries below.&lt;/span>&lt;/p>
&lt;h3 id="span-stronginstallationstrongspan">&lt;span >&lt;strong>Installation&lt;/strong>&lt;/span>&lt;/h3>
&lt;p>&lt;span >&lt;strong>&lt;em>Python&lt;/em>&lt;/strong>&lt;/span>&lt;/p>
&lt;p>&lt;span >on the command line&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:sh decode:true">&lt;span >pip install habanero&lt;/span>&lt;/pre>
&lt;p>&lt;span >&lt;em>&lt;strong>Ruby&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;p>&lt;span >on the command line&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:sh decode:true">&lt;span >gem install serrano&lt;/span>&lt;/pre>
&lt;p>&lt;span >&lt;em>&lt;strong>R&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;p>&lt;span >in an R session&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:r decode:true">&lt;span >install.packages("rcrossref")&lt;/span>&lt;/pre>
&lt;p> &lt;/p>
&lt;h3 id="span-strongexamplesstrongspan">&lt;span >&lt;strong>Examples&lt;/strong>&lt;/span>&lt;/h3>
&lt;p>&lt;span >Output is indicated by the syntax &lt;code>#&amp;gt;&lt;/code> in all examples below.&lt;/span>&lt;/p>
&lt;p>&lt;span >&lt;em>&lt;strong>Python&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;p>&lt;span >in a Python REPL (e.g. &lt;em>iPython&lt;/em>)&lt;/span>&lt;/p>
&lt;p>&lt;span >Import the &lt;em>Crossref&lt;/em> module from within &lt;em>habanero&lt;/em>, and initialize a client&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:python decode:true">&lt;span >from habanero import Crossref
cr = Crossref()&lt;/span>&lt;/pre>
&lt;p>&lt;span >Query for the phrase “ecology”&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:python decode:true">&lt;span >x = cr.works(query = "ecology", limit = 5)&lt;/span>&lt;/pre>
&lt;p>&lt;span >Index to various parts of the output&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:python decode:true">&lt;span >x['message']['total-results']
#&amp;gt; 276188&lt;/span>&lt;/pre>
&lt;p>&lt;span >Extract similar data items from each result. The records are in the “items” slot&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:python decode:true">&lt;span >[ z['DOI'] for z in x['message']['items'] ]
#&amp;gt; [u'10.1002/(issn)1939-9170',
#&amp;gt; u'10.4996/fireecology',
#&amp;gt; u'10.5402/ecology',
#&amp;gt; u'10.1155/8641',
#&amp;gt; u'10.1111/(issn)1439-0485']&lt;/span>&lt;/pre>
&lt;p>&lt;span >In &lt;em>habanero&lt;/em> for some methods we require you to instantiate a client.&lt;/span>&lt;/p>
&lt;p>&lt;span >You can set a base URL and API key. This is a future looking feature&lt;/span>&lt;/p>
&lt;p>&lt;span >as Crossref API does not require an API key.&lt;/span>&lt;/p>
&lt;p>&lt;span >Note: I’ve tried to make sure habanero is Python 2 and 3 compatible. Hopefully you’ll find that’s true.&lt;/span>&lt;/p>
&lt;p>&lt;span >&lt;em>&lt;strong>Ruby&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;p>&lt;span >in a Ruby repl (e.g., &lt;a href="https://web.archive.org/web/20160312125404/http://pryrepl.org//">pry&lt;/a>), load &lt;em>serrano&lt;/em>&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:ruby decode:true ">&lt;span >require 'serrano'&lt;/span>&lt;/pre>
&lt;p>&lt;span >Query for “peerj” on the journals route&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:ruby decode:true">&lt;span >x = Serrano.journals(query: "peerj")&lt;/span>&lt;/pre>
&lt;p>&lt;span >Collect just ISSN’s from each result&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:ruby decode:true">&lt;span >x['message']['items'].collect { |z| z['ISSN'] }
#&amp;gt; =&amp;gt; [["2376-5992"], ["2167-8359"]]&lt;/span>&lt;/pre>
&lt;p> &lt;/p>
&lt;p>&lt;span >&lt;em>&lt;strong>Shell&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;p>&lt;span >The &lt;code>serrano&lt;/code> command line tool is quite powerful if you are used to doing things there.&lt;/span>&lt;/p>
&lt;p>&lt;span >Here, search for one article; summary data is shown.&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:sh decode:true">&lt;span >serrano works 10.1371/journal.pone.0033693
#&amp;gt; DOI: 10.1371/journal.pone.0033693
#&amp;gt; type: journal-article
#&amp;gt; title: Methylphenidate Exposure Induces Dopamine Neuron Loss and Activation of Microglia in the Basal Ganglia of Mice&lt;/span>&lt;/pre>
&lt;p>&lt;span >There’s also a &lt;code>-json&lt;/code> flag to give back JSON data, which can be parsed with the command line tool &lt;a href="https://stedolan.github.io/jq/">jq&lt;/a>.&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:sh decode:true">&lt;span >serrano works --filter=has_full_text:true --json --limit=5 | jq '.message.items[].link[].URL'
#&amp;gt; "http://api.wiley.com.pluma.sjfc.edu/onlinelibrary/tdm/v1/articles/10.1002%2F9781119208082.ch9"
#&amp;gt; "http://api.wiley.com.pluma.sjfc.edu/onlinelibrary/tdm/v1/articles/10.1002%2F9781119208082.index"
#&amp;gt; "http://api.wiley.com.pluma.sjfc.edu/onlinelibrary/tdm/v1/articles/10.1002%2F9781119208082.ch11"
#&amp;gt; "http://api.wiley.com.pluma.sjfc.edu/onlinelibrary/tdm/v1/articles/10.1002%2F9781119208082.ch15"
#&amp;gt; "http://api.wiley.com.pluma.sjfc.edu/onlinelibrary/tdm/v1/articles/10.1002%2F9781119208082.ch4"&lt;/span>&lt;/pre>
&lt;p> &lt;/p>
&lt;p>&lt;span >&lt;em>&lt;strong>R&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;p>&lt;span >In an R session, load &lt;code>rcrossref&lt;/code>&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:r decode:true ">&lt;span >library("rcrossref")&lt;/span>&lt;/pre>
&lt;p>&lt;span >Search the &lt;code>works&lt;/code> route for the phrase “science”&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:r decode:true">&lt;span >res &amp;lt;- cr_works(query = "science", limit = 5)
#&amp;gt; $meta
#&amp;gt; total_results search_terms start_index items_per_page
#&amp;gt; 1 4333827 science 0 5
#&amp;gt;
#&amp;gt; $data
#&amp;gt; Source: local data frame [5 x 23]
#&amp;gt;
#&amp;gt; alternative.id container.title created deposited DOI funder indexed
#&amp;gt; (chr) (chr) (chr) (chr) (chr) (chr) (chr)
#&amp;gt; 1 2013-11-21 2013-11-21 10.1126/science &amp;lt;NULL&amp;gt; 2015-12-27
#&amp;gt; 2 Science Askew 2004-11-26 2013-12-16 10.1887/0750307145/b426c18 &amp;lt;NULL&amp;gt; 2015-12-24
#&amp;gt; 3 2006-04-10 2010-07-30 10.1002/(issn)1557-6833 &amp;lt;NULL&amp;gt; 2015-12-25
#&amp;gt; 4 2013-08-27 2013-08-27 10.1002/(issn)1469-896x &amp;lt;NULL&amp;gt; 2015-12-27
#&amp;gt; 5 2013-12-19 2013-12-19 10.5152/bs. &amp;lt;NULL&amp;gt; 2015-12-28
#&amp;gt; Variables not shown: ISBN (chr), ISSN (chr), issued (chr), link (chr), member (chr), prefix (chr), publisher
#&amp;gt; (chr), reference.count (chr), score (chr), source (chr), subject (chr), title (chr), type (chr), URL
#&amp;gt; (chr), assertion (chr), author (chr)
#&amp;gt;
#&amp;gt; $facets
#&amp;gt; NULL&lt;/span>&lt;/pre>
&lt;p>&lt;span >Index through to get the DOIs&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:r decode:true">&lt;span >res$data$DOI
#&amp;gt; [1] "10.1126/science" "10.1887/0750307145/b426c18" "10.1002/(issn)1557-6833"
#&amp;gt; [4] "10.1002/(issn)1469-896x" "10.5152/bs."&lt;/span>&lt;/pre>
&lt;blockquote>
&lt;p>&lt;span >rcrossref also has faster versions of most functions with an underscore at the end (&lt;code>_&lt;/code>) which only do the http request and give back json (e.g., &lt;code>cr_works_()&lt;/code>)&lt;/span>&lt;/p>
&lt;/blockquote>
&lt;h3 id="span-strongcomparisonof-crossref-client-methodsstrongspan">&lt;span >&lt;strong>Comparison of Crossref Client Methods&lt;/strong>&lt;/span>&lt;/h3>
&lt;p>&lt;span >After installation and loading the libraries above, the below methods are available&lt;/span>&lt;/p>
&lt;table style="width: 100%;">
&lt;tr>
&lt;th>
&lt;span >API Route&lt;/span>
&lt;/th>
&lt;pre>&lt;code>&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;Python&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;Ruby&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;R&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>works&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.works()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.works()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_works()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>members&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.members()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.members()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_members()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>funders&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.funders()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.funders()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_funders()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>types&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.types()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.types()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_types()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>licenses&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.licenses()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.licenses()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_licenses()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>journals&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.journals()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.journals()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_journals()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>members&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.members()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.members()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_members()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>registration agency&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.registration_agency()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.registration_agency()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_agency()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>random DOIs&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr.random_dois()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.random_dois()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_r()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;/table>
&lt;h3 id="span-strongother-crossref-servicesstrongspan">&lt;span >&lt;strong>Other Crossref Services&lt;/strong>&lt;/span>&lt;/h3>
&lt;table style="width: 100%;">
&lt;tr>
&lt;th>
&lt;span >Service&lt;/span>
&lt;/th>
&lt;pre>&lt;code>&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;Python&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;Ruby&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;R&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>content negotiation&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cn.content_negotiation()&amp;lt;/code&amp;gt;&amp;lt;a href=&amp;quot;#footnote-1&amp;quot;&amp;gt;[1]&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.content_negotiation()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_cn()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>CSL styles&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cn.csl_styles()&amp;lt;/code&amp;gt;&amp;lt;a href=&amp;quot;#footnote-1&amp;quot;&amp;gt;[1]&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.csl_styles()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;get_styles()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>citation count&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;counts.citation_count()&amp;lt;/code&amp;gt;&amp;lt;a href=&amp;quot;#footnote-2&amp;quot;&amp;gt;[2]&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano.citation_count()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;cr_citation_count()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;/table>
&lt;p id="footnote-1">
&lt;span >[1] &lt;code>from habanero import cn&lt;/code>&lt;/span>
&lt;/p>
&lt;p id="footnote-2">
&lt;span >[2] &lt;code>from habanero import counts&lt;/code>&lt;/span>
&lt;/p>
&lt;p> &lt;/p>
&lt;h3 id="span-featuresspan">&lt;span >Features&lt;/span>&lt;/h3>
&lt;p>&lt;span >These are supported in all 3 libraries:&lt;/span>&lt;/p>
&lt;ul>
&lt;li>&lt;span >Filters (see below)&lt;/span>&lt;/li>
&lt;li>&lt;span >Deep paging (see below)&lt;/span>&lt;/li>
&lt;li>&lt;span >Pagination&lt;/span>&lt;/li>
&lt;li>&lt;span >Verbose curl output&lt;/span>&lt;/li>
&lt;/ul>
&lt;h3 id="span-filtersspan">&lt;span >Filters&lt;/span>&lt;/h3>
&lt;p>&lt;span >Filters (see &lt;a href="https://github.com/Crossref/rest-api-doc/blob/master/rest_api.md#filter-names">API docs&lt;/a> for details) are a powerful way to get closer to exactly what you want in your queries. In the Crossref API filters are passed as query parameters, and are comma-separated like &lt;span class="lang:default decode:true crayon-inline ">filter=has-orcid:true,is-update:true&lt;/span> . In the client libraries, filters are passed in idiomatic fashion according to the language.&lt;/span>&lt;/p>
&lt;p>&lt;span >&lt;em>&lt;strong>Python&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:python decode:true">&lt;span >from habanero import Crossref
cr = Crossref()
cr.works(filter = {'award_number': 'CBET-0756451', 'award_funder': '10.13039/100000001'})&lt;/span>&lt;/pre>
&lt;p>&lt;span >&lt;em>&lt;strong>Ruby&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:ruby decode:true">&lt;span >require 'serrano'
Serrano.works(filter: {award_number: 'CBET-0756451', award_funder: '10.13039/100000001'})&lt;/span>&lt;/pre>
&lt;p>&lt;span >&lt;em>&lt;strong>R&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:r decode:true">&lt;span >library("rcrossref")
cr_works(filter=c(award_number=TRUE, award_funder='10.13039/100000001'))
&lt;/span>&lt;/pre>
&lt;p>&lt;span >Note how syntax is quite similar among languages, though keys don’t have to be quoted in Ruby and R, and in R you pass in a vector or list instead of a hash as in the other two.&lt;/span>&lt;/p>
&lt;p>&lt;span >All 3 clients have helper functions to show you what filters are available and what the options are for each filter.&lt;/span>&lt;/p>
&lt;table style="width: 100%;">
&lt;tr>
&lt;th>
&lt;span >Action&lt;/span>
&lt;/th>
&lt;pre>&lt;code>&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;Python&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;Ruby&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;
&amp;lt;span &amp;gt;R&amp;lt;/span&amp;gt;
&amp;lt;/th&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>Filter names&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;filters.filter_names&amp;lt;/code&amp;gt;&amp;lt;a href=&amp;quot;#footnote-3&amp;quot;&amp;gt;[3]&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano::Filters.names&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;filter_names()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;span >&lt;strong>Filter details&lt;/strong>&lt;/span>
&lt;/td>
&lt;pre>&lt;code>&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;filters.filter_details&amp;lt;/code&amp;gt;&amp;lt;a href=&amp;quot;#footnote-3&amp;quot;&amp;gt;[3]&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;Serrano::Filters.filters&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
&amp;lt;span &amp;gt;&amp;lt;code&amp;gt;filter_details()&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/code>&lt;/pre>
&lt;/tr>
&lt;/table>
&lt;p id="footnote-3">
&lt;span >[3] &lt;code>from habanero import filters&lt;/code>&lt;/span>
&lt;/p>
&lt;p> &lt;/p>
&lt;h3 id="span-deep-pagingspan">&lt;span >Deep paging&lt;/span>&lt;/h3>
&lt;p>&lt;span >Sometimes you want a lot of data. The Crossref API has parameters for paging (see &lt;a href="https://github.com/Crossref/rest-api-doc/blob/master/rest_api.md#rows">rows&lt;/a> and &lt;a href="https://github.com/Crossref/rest-api-doc/blob/master/rest_api.md#offset">offset&lt;/a>), but large values of either can lead to long response times and potentially timeouts (i.e., request failure). The API has a deep paging feature that can be used when large data volumes are desired. This is made possible via Solr’s cursor feature (e.g., &lt;a href="http://solr.pl/en/2014/03/10/solr-4-7-efficient-deep-paging/">blog post on it&lt;/a>). Here’s a run down of how to use it:&lt;/span>&lt;/p>
&lt;ul>
&lt;li>&lt;span >&lt;code>cursor&lt;/code>: each method in each client library that allows deep paging has a &lt;code>cursor&lt;/code> parameter that if you set to &lt;code>*&lt;/code> will tell the Crossref API you want deep paging.&lt;/span>&lt;/li>
&lt;li>&lt;span >&lt;code>cursor_max&lt;/code>: for boring reasons we need to have feedback from the user when they want to stop, since each request comes back with a cursor value that we can make the next request with, thus, an additional parameter &lt;code>cursor_max&lt;/code> is used to indicate the number of results you want back.&lt;/span>&lt;/li>
&lt;li>&lt;span >&lt;code>limit&lt;/code>: this parameter when not using deep paging determines number of results to get back. however, when deep paging, this parameter sets the chunk size. (note that the max. value for this parameter is 1000)&lt;/span>&lt;/li>
&lt;/ul>
&lt;p>&lt;span >For example, &lt;code>cursor=&amp;amp;#8221;*&amp;amp;#8221;&lt;/code> states that you want deep paging, &lt;code>cursor_max&lt;/code> states maximum results you want back, and &lt;code>limit&lt;/code> determines how many results per request to fetch.&lt;/span>&lt;/p>
&lt;p>&lt;span >&lt;em>&lt;strong>Python&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:python decode:true ">&lt;span >from habanero import Crossref
cr = Crossref()
cr.works(query = "widget", cursor = "*", cursor_max = 500)&lt;/span>&lt;/pre>
&lt;p>&lt;span >&lt;em>&lt;strong>Ruby&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:ruby decode:true">&lt;span >require 'serrano'
Serrano.works(query: "widget", cursor: "*", cursor_max: 500)&lt;/span>&lt;/pre>
&lt;p>&lt;span >&lt;em>&lt;strong>R&lt;/strong>&lt;/em>&lt;/span>&lt;/p>
&lt;pre class="theme:solarized-light lang:r decode:true">&lt;span >library("rcrossref")
cr_works(query = "widget", cursor = "*", cursor_max = 500)
&lt;/span>&lt;/pre>
&lt;p> &lt;/p>
&lt;h3 id="span-text-mining-clientsspan">&lt;span >Text mining clients&lt;/span>&lt;/h3>
&lt;p>&lt;span >Just a quick note that I’ve begun a few text-mining clients for Python and Ruby, focused on using the low level clients discussed above.&lt;/span>&lt;/p>
&lt;ul>
&lt;li>&lt;span >Python: &lt;a href="https://github.com/sckott/pyminer">&lt;a href="https://github.com/sckott/pyminer" target="_blank">https://github.com/sckott/pyminer&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;li>&lt;span >Ruby: &lt;a href="https://github.com/sckott/textminer">&lt;a href="https://github.com/sckott/textminer" target="_blank">https://github.com/sckott/textminer&lt;/a>&lt;/a>&lt;/span>&lt;/li>
&lt;/ul>
&lt;p>&lt;span >Do try them out!&lt;/span>&lt;/p></description></item><item><title>DOIs and matching regular expressions</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/dois-and-matching-regular-expressions/</link><pubDate>Tue, 11 Aug 2015 00:00:00 +0000</pubDate><author>Andrew Gilmartin</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/dois-and-matching-regular-expressions/</guid><description>&lt;p>&lt;span >We regularly see developers using regular expressions to validate or scrape for DOIs. For modern Crossref DOIs the regular expression is short&lt;/span>&lt;/p>
&lt;p>&lt;code>/^10.\d{4,9}/[-._;()/:A-Z0-9]+$/i&lt;/code>&lt;/p>
&lt;p>&lt;span >For the 74.9M DOIs we have seen this matches 74.4M of them. If you need to use only one pattern then use this one.&lt;/p>
&lt;/span>
&lt;p>&lt;span >The other 500K are mostly from Crossref’s early days when the battle between “human-readable” identifiers and “opaque” identifiers was still being fought, the web was still new, and it was expected that “doi” would become as well a supported URI schema name as “gopher”, “wais”, …. Ok, that didn’t go so well.&lt;/span>&lt;/p>
&lt;p>&lt;span >An early Crossref’s member was John Wiley &amp;amp; Sons. They faced the need to design DOIs without much prior work to lean on. Many of those early DOIs are not expression friendly. Nevertheless, they are still valid and valuable permanent links to the work’s version of record. You can catch 300K more DOIs with&lt;/span>&lt;/p>
&lt;p>&lt;code>/^10.1002/[^\s]+$/i&lt;/code>&lt;/p>
&lt;p>&lt;span >While the DOI caught is likely to be the DOI within the text it may also contain trailing characters that, due to the lack of a space, are caught up with the DOI. Even the recommended expression catches DOIs ending with periods, colons, semicolons, hyphens, and underscores. Most DOIs found in the wild are presented within some visual design program. While pleasant to look at the visual design can misdirect machines. Is the period at the end of the line part of the DOI or part of the design? Is that endash actually a hyphen? These issues lead to a DOI bycatch.&lt;/span>&lt;/p>
&lt;p>&lt;span >Adding the following 3 expressions with the previous 2 leaves only 72K DOIs uncaught. To catch these 72K would require a dozen or more additional patterns. Each additional pattern, unfortunately, weakens the overall precision of the catch. More bycatch.&lt;/span>&lt;/p>
&lt;p>&lt;code>/^10.\d{4}/\d+-\d+X?(\d+)\d+&amp;lt;[\d\w]+:[\d\w]*&amp;gt;\d+.\d+.\w+;\d$/i&lt;/code>&lt;/p>
&lt;p>&lt;code>/^10.1021/\w\w\d++$/i&lt;/code>&lt;/p>
&lt;p>&lt;code>/^10.1207/[\w\d]+\&amp;amp;\d+_\d+$/i&lt;/code>&lt;/p>
&lt;p>&lt;span >Crossref is not the only DOI Registration Agency and while our members account for 65-75% of all registered DOIs this means there are tens of millions of DOIs that we have not seen. Luckily, the newer RAs and their publishers can copy our successes and avoid our mistakes.&lt;/span>&lt;/p></description></item><item><title>Content Negotiation for Crossref DOIs</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/content-negotiation-for-crossref-dois/</link><pubDate>Tue, 19 Apr 2011 00:00:00 +0000</pubDate><author>Geoffrey Bilder</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/content-negotiation-for-crossref-dois/</guid><description>&lt;p>&lt;span >So does anybody remember the posting &lt;a href="https://www-crossref-org.pluma.sjfc.edu/blog/dois-and-linked-data-some-concrete-proposals/">DOIs and Linked Data: Some Concrete Proposals&lt;/a>?&lt;/span>&lt;/p>
&lt;p>&lt;span >Well, we went with option “D.”&lt;/span>&lt;/p>
&lt;p>&lt;span >From now on, DOIs, &lt;i>expressed as &lt;a href="http://en.wikipedia.org/wiki/Uniform_Resource_Identifier">HTTP URI&lt;/a>s&lt;/i>, can be used with &lt;a href="http://en.wikipedia.org/wiki/Content_negotiation">content-negotiation&lt;/a>.&lt;/span>&lt;/p>
&lt;p>&lt;span >Let’s get straight to the point. If you have &lt;a href="http://curl.haxx.se/">curl&lt;/a> installed, you can start playing with content-negotiation and Crossref DOIs right away:&lt;/span>&lt;/p>
&lt;blockquote>
&lt;p>&lt;span >curl -D - -L -H   “Accept: application/rdf+xml” “&lt;code>http://dx.doi.org.pluma.sjfc.edu/10.1126/science.1157784&lt;/code>” &lt;/span>&lt;/p>
&lt;p>&lt;span >curl -D - -L -H   “Accept: text/turtle” “&lt;code>http://dx.doi.org.pluma.sjfc.edu/10.1126/science.1157784&lt;/code>”&lt;br /> &lt;/span>&lt;/p>
&lt;p>&lt;span >curl -D - -L -H   “Accept: application/atom+xml” “&lt;code>http://dx.doi.org.pluma.sjfc.edu/10.1126/science.1157784&lt;/code>” &lt;/span>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;span >Or if you are already using Crossref’s “&lt;a href="https://www-crossref-org.pluma.sjfc.edu/schema/unixref1.1.xsd" target="_blank">unixref&lt;/a>” format:&lt;/span>&lt;/p>
&lt;blockquote>
&lt;p>&lt;span >curl -D - -L -H “Accept: application/unixref+xml” “&lt;code>http://dx.doi.org.pluma.sjfc.edu/10.1126/science.1157784&amp;amp;&lt;/code>#8221; &lt;/span>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;span >This will work with over 46 million Crossref DOIs as of today, but the beauty of the setup is that from now on, any &lt;a href="http://www.doi.org.pluma.sjfc.edu/registration_agencies.html">DOI registration agency&lt;/a> can enable content negotiation for their constituencies as well. &lt;a href="http://datacite.org/">DataCite&lt;/a>- we’re looking at you 😉 .&lt;/span>&lt;/p>
&lt;p>&lt;span >It also means that, as registration agency members (Crossref publishers, for instance) start providing more complete and richer representations of their content, we can simply redirect content-negotiated requests directly to them.&lt;/span>&lt;/p>
&lt;p>&lt;span >We expect that that this development will round-out Crossref’s efforts to support standard APIs including &lt;a href="https://support-crossref-org.pluma.sjfc.edu/hc/en-us/articles/214880143">OpenURL&lt;/a> and &lt;a href="https://support-crossref-org.pluma.sjfc.edu/hc/en-us/articles/213679866">OAI_PMH&lt;/a> and we look forward to seeing DOIs increasingly used in &lt;a href="http://en.wikipedia.org/wiki/Linked_Data">linked data&lt;/a> applications.&lt;/span>&lt;/p>
&lt;p>&lt;span >Finally, Crossref would just like to thank the &lt;a href="http://www.doi.org.pluma.sjfc.edu/foundation/bios.html">IDF&lt;/a> and &lt;a href="http://www.cnri.reston.va.us/">CNRI&lt;/a> for their hard work on this as well as &lt;a href="http://www.linkedin.com/in/tonyhammond">Tony Hammond&lt;/a> and &lt;a href="http://www.ldodds.com/">Leigh Dodds&lt;/a> for their valuable advice and persistent goading.&lt;/span>&lt;/p></description></item><item><title>Ubiquity commands for Crossref services</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/ubiquity-commands-for-crossref-services/</link><pubDate>Wed, 03 Dec 2008 00:00:00 +0000</pubDate><author>Geoffrey Bilder</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/ubiquity-commands-for-crossref-services/</guid><description>&lt;p>So the other day &lt;a href="http://baoilleach.blogspot.com/" target="_blank">Noel O’Boyle&lt;/a> made me feel guilty when he pinged me and asked about the possibility using one of the Crossref APIs for creating a &lt;a href="https://wiki.mozilla.org/Labs/Ubiquity" target="_blank">Ubiquity&lt;/a> extension. You see, I had played with the idea myself and had not gotten around to doing much about it. This seemed inexcusable- particularly given how easy it is to build such extensions using the API we developed for the &lt;a href="http://sourceforge.net/projects/crossref-cite/" target="_blank">WordPress and Moveable Type plugins&lt;/a> that we &lt;a href="https://www-crossref-org.pluma.sjfc.edu/blog/crossref-citation-plugin-for-wordpress/">announced&lt;/a> earlier in the year. So I dug up my half-finished code, cleaned it up a bit and have &lt;a href="https://www-crossref-org.pluma.sjfc.edu/labs/ubiquity-plugin/" target="_blank">posted the results.&lt;/a>&lt;/p>
&lt;p>Note that the back-end that supports the plugins has been moved to more stable machines and the index is now being automatically updated with journal and conference proceeding deposits (sorry, no books yet).&lt;/p>
&lt;p>Also note that we are hoping that others will look at the code for the WordPress, Moveable Type and Ubiquity plugins and create more such extensions. If you do, please let us know about them at &lt;a href="mailto:citation-plugin@crossref.org">citation-plugin@crossref.org&lt;/a>.&lt;/p></description></item><item><title>Kay Sera Sera</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/kay-sera-sera/</link><pubDate>Tue, 20 Feb 2007 00:00:00 +0000</pubDate><author>Crossref</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/kay-sera-sera/</guid><description>&lt;p>Not specifically publishing-related, but here is a fun &lt;strike>rant &lt;/strike>&lt;a href="http://www.cioinsight.com/print_article2/0,1217,a=200162,00.asp" target="_blank">interview&lt;/a> with &lt;a href="http://en.wikipedia.org/wiki/Alan_Kay" target="_blank">Alan Kay&lt;/a> titled &lt;em>The PC Must Be Revamped—Now.&lt;/em>&lt;/p>
&lt;p>My favorite bit…&lt;/p>
&lt;p>“…in the last few years I’ve been asking computer scientists and programmers whether they’ve ever typed E-N-G-E-L-B-A-R-T into Google-and none of them have. I don’t think you could find a physicist who has not gone back and tried to find out what Newton actually did. It’s unimaginable. Yet the computing profession acts as if there isn’t anything to learn from the past, so most people haven’t gone back and referenced what Engelbart thought. ”&lt;/p></description></item><item><title>Stick this in your pipe&amp;#8230;</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/stick-this-in-your-pipe/</link><pubDate>Mon, 19 Feb 2007 00:00:00 +0000</pubDate><author>Crossref</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/stick-this-in-your-pipe/</guid><description>&lt;p>&lt;a href="http://www2.blogger.com/profile/12568103499947976875" target="_blank">Rob Cornelius&lt;/a> has a &lt;a href="http://allmyeye.blogspot.com/index.html" target="_blank">practical little demo&lt;/a> of using Yahoo! pipes against some Ingenta feeds.&lt;/p>
&lt;p>Like Tony, I keep experiencing speed/stability problems while accessing pipes so I haven’t yet become a &lt;a href="http://www.researchbuzz.org/wp/2007/02/12/yahoo-ruins-my-life-with-yahoo-pipes/" target="_blank">crack-pipes-head&lt;/a>.&lt;/p></description></item><item><title>Ruby Makes A-List</title><link>https://www-crossref-org.pluma.sjfc.edu/blog/ruby-makes-alist/</link><pubDate>Thu, 12 Oct 2006 00:00:00 +0000</pubDate><author>Tony Hammond</author><guid>https://www-crossref-org.pluma.sjfc.edu/blog/ruby-makes-alist/</guid><description>&lt;p>Um, well. Seems according to &lt;a href="http://www.oreillynet.com/ruby/blog/2006/10/ruby_declared_mainstream.html" target="_blank">O’Reilly Ruby&lt;/a> that Ruby is now a mainstream language.&lt;/p>
&lt;p>&lt;em>“The &lt;a href="http://www.ruby-lang.org/" target="_blank">Ruby programming language&lt;/a> just made the A-list on the &lt;a href="http://www.tiobe.com" target="_blank">TIOBE Programming Community Index&lt;/a>, and Ruby is now listed as a mainstream programming language. For the past three or four years Ruby has consistently placed in the high 20’s in this index, but is now placed as the 13th most popular programming language!”&lt;/em>&lt;/p>
&lt;p>(No language wars, but I am, I will confess, a big admirer - for some time.)&lt;/p></description></item></channel></rss>