- RATIONALE & METHOD
- SEE ALSO
- LICENSE AND COPYRIGHT
Data::UUID::NCName - Make valid NCName tokens which are also UUIDs
use Data::UUID::NCName qw(:all); my $uuid = '1ff916f3-6ed7-443a-bef5-f4c85f18cd10'; my $ncn = to_ncname($uuid); my $ncn32 = to_ncname($uuid, 32); # $ncn is now "EH_kW827XQ6vvX0yF8YzRA". # $ncn32 is "Ed74rn43o25b2x327jsc7ddgra" and case-insensitive. # from Test::More, this will output 'ok': is(from_ncname($ncn), $uuid, 'Decoding result matches original');
The purpose of this module is to devise an alternative representation of the UUID which conforms to the constraints of various other identifiers such as NCName, and create an isomorphic mapping between them.
The UUID is a generic identifier which is large enough to be globally unique. This makes it useful as a canonical name for data objects in distributed systems, especially those that cross administrative jurisdictions, such as the World-Wide Web. The representation, however, of the UUID, precludes it from being used in many places where it would be useful to do so.
In particular, there are grammars for many types of identifiers which must not begin with a digit. Others are case-insensitive, or prohibited from containing hyphens (present in both the standard notation and Base64URL), or indeed anything outside of
The hexadecimal notation of the UUID has a 5/8 chance of beginning with a digit, Base64 has a 5/32 chance, and Base32 has a 3/16 chance. As such, the identifier must be modified in such a way as to guarantee beginning with an alphabetic letter (or underscore
_, but some grammars even prohibit that, so we omit it as well).
While it is conceivable to simply add a padding character, there are a few considerations which make it more appealing to derive the initial character from the content of the UUID itself:
UUIDs are large (128-bit) identifiers as it is, and it is undesirable to add meaningless syntax to them if we can avoid doing so.
128 bits is an inconvenient number for aligning to both Base32 (130) and Base64 (132), though 120 divides cleanly into 5, 6 and 8.
The 13th quartet, or higher four bits of the
time_hi_and_version_fieldof the UUID is constant, as it indicates the UUID's version. If we encode this value using the scheme common to both Base64 and Base32, we get values between
P, with the valid subset between
Therefore: extract the UUID's version quartet, shift all subsequent data 4 bits to the left, zero-pad to the octet, encode with either base64url or base32, truncate, and finally prepend the encoded version character. Voilà, one token-safe UUID.
- XML IDs
IDproduction appears to have been constricted, inadvertently or otherwise, from Name in both the XML 1.0 and 1.1 specifications, to NCName by XML Schema Part 2. This removes the colon character
:from the grammar. The net effect is that
while being a well-formed ID and valid under DTD validation, is not valid per XML Schema Part 2 or anything that uses it (e.g. Relax NG).
- RDF blank node identifiers
Blank node identifiers in RDF are intended for serialization, to act as a handle so that multiple RDF statements can refer to the same blank node. The RDF abstract syntax specifies that the validity constraints of blank node identifiers be delegated to the concrete syntax specifications. The RDF/XML syntax specification lists the blank node identifier as NCName. However, according to the Turtle spec, this is a valid blank node identifier:
- Generated symbols
There are only two hard things in computer science: cache invalidation and naming things [and off-by-one errors].
-- Phil Karlton [extension of unknown origin]
Suppose you wanted to create a literate programming system (I do). One of your (my) stipulations is that the symbols get defined in the prose, rather than the code. However, you (I) still want to be able to validate the code's syntax, and potentially even run the code, without having to commit to naming anything. You are (I am) also interested in creating a global map of classes, datatypes and code fragments, which can be operated on and tested in isolation, ported to other languages, or transplanted into the more conventional packages of programs, libraries and frameworks. The Base32 UUID NCName representation should be adequate for placeholder symbols in just about any programming language, save for those which do not permit identifiers as long as 26 characters (which are extremely scarce).
No subroutines are exported by default. Be sure to include at least one of the following in your
Import all functions.
Import decode-only functions.
Import encode-only functions.
Import base32-only functions.
Import base64-only functions.
$UUID into an NCName. The UUID can be in the canonical (hyphenated) hexadecimal form, non-hyphenated hexadecimal, Base64 (regular and base64url), or binary. The function returns a legal NCName equivalent to the UUID, in either Base32 or Base64 (url), given a specified
$RADIX of 32 or 64. If the radix is omitted, Base64 is assumed.
Turn an appropriate
$NCNAME back into a UUID, where appropriate, unless overridden by
$RADIX, is defined beginning with one initial alphabetic letter (A to Z, case-insensitive) followed by either:
The function will return
undef immediately if it cannot match either of these patterns. Input past the 21-character mark (for Base64) or 25-character mark (for Base32) is ignored.
This function returns a UUID of type
$FORMAT, which if left undefined, must be one of the following:
The canonical UUID format, like so:
33fcc995-5d10-477e-a9b4-c9cc405bbf04. This is the default.
The same thing, minus the hyphens.
A binary string.
Shorthand for Base64 NCNames.
Shorthand for Base32 NCNames.
<dorian at cpan.org>
Please report any bugs or feature requests to
bug-data-uuid-ncname at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Data-UUID-NCName. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
You can find documentation for this module with the perldoc command.
You can also look for information at:
RT: CPAN's request tracker (report bugs here)
AnnoCPAN: Annotated CPAN documentation
- RFC 4122
- RFC 4648
- Namespaces in XML (NCName)
- W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes (ID)
- RDF/XML Syntax Specification (Revised)
This module lives under the
Data:: namespace for the purpose of hygiene. It does not depend on Data::UUID or any other UUID modules.
Copyright 2012 Dorian Taylor.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 .
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.