This post originated from an RSS feed registered with Java Buzz
by Bill de hÓra.
Original Post: Automated mapping between RDF and forms, part I
Feed Title: Bill de hÓra
Feed URL: http://www.dehora.net/journal/atom.xml
Feed Description: FD85 1117 1888 1681 7689 B5DF E696 885C 20D8 21F8
Let's start with some FOAF, that shows some issues around roundtripping RDF data through a web form. Foaf only has one property for a phone, namely foaf:phone. It has like, much values for IM, but not for phones: <rdf:Description rdf:about="http://example.com/person/elvis"> <foaf:phone rdf:resource="tel:987654321"/> <foaf:phone rdf:resource="tel:123456789"/> </rdf:Description> So how do you distinguish between your home, work phones and 2 mobiles? No worries, let's type annotate these little jokers: <rdf:Description rdf:about="http://example.com/person/elvis"> <foaf:phone rdf:resource="tel:987654321"/> <foaf:phone rdf:resource="tel:123456789"/> </rdf:Description> <rdf:Description rdf:about="tel:987654321"> <rdf:type rdf:resource="urn:mobile"/> </rdf:Description> <rdf:Description rdf:about="tel:123456789"> <rdf:type rdf:resource="urn:work"/> </rdf:Description> In psuedo-excel that looks like this: foaf:person, foaf:phone, tel:987654321 foaf:person, foaf:phone, tel:123456789 tel:987654321, rdf:type, urn:mobile tel:123456789, rdf:type, urn:work Sorted. But not for forms. Suppose you want to send down those two phone values to a form. You can divvy them based on the RDF type annotation (this one's a mobile, that one's for work) without too much trouble. This is what the form fragment might look like: <p> <label for="work">work:</label> <input size="25" value="tel:123456789" type="text" name="foaf_phone_work"> <input type="checkbox" id="delete_foaf_phone_work" >delete</input> </p> <p> <label for="mobile">mobile:</label> <input size="25" value="tel:987654321" type="text" name="foaf_phone_mobile"> <input type="checkbox" id="delete_foaf_phone_mobile" >delete</input> </p> There's some name munging ("foaf_phone_mobile", "foaf_phone_work") as you can see, but that's ok. But on the way back if you have more than one foaf:phone value, things get tricky. That's because after the reversing the name munging and mapped the "foaf_phone_mobile" back, the way you're going to update a value typically is to find it first by matching against the subject/property and wildcard the value, thus: foaf:person, foaf:phone, ??? That would work for the typical case where you only have one possible property/value, but won't distinguish between the two phone property/values we have here. If you were using a delete/insert approach, the chances are you'd end up overwriting the wrong one, or worse, blowing one of the phone values out of the datastore. So we need to use a richer pattern, after getting the form data back. Something like this that leverages the type annotations we declared would do it: foaf:person, foaf:phone, ??? ???, rdf:type, urn:mobile But. When you have two mobile phones you'll need even further name munging because the above pattern isn't sufficient to pick out the right phone anymore. Generally you'll end up doing something like this: <p> <label for="work">work:</label> <input size="25" value="tel:123456789" type="text" name="foaf_phone_work_14387975"> <input type="checkbox" id="delete_foaf_phone_work_14387975" >delete</input> </p> <p> <label for="mobile">mobile:</label> <input size="25" value="tel:987654321" type="text" name="foaf_phone_mobile_3434535"> <input type="checkbox" id="delete_foaf_phone_mobile_3434535" >delete</input> </p> If you don't, one day the form will blow up the data. Normally you'd manage the roundtrip through the web tier. That means there's a hashmap somewhere tying up the RDF with the name "foaf_phone_work_14387975". The other way to do this, if you don't minding hitting the storage in the interim, is to write the name value to the datastore first and relate it to the phone number: foaf:person, foaf:phone, tel:987654321 foaf:person, foaf:phone, tel:123456789 tel:987654321, rdf:type, urn:mobile tel:123456789, rdf:type, urn:work tel:987654321, form:bind, foaf_phone_mobile_3434535 tel:123456789, form:bind, foaf_phone_work_14387975 Now we're looking for the pattern: foaf:person, foaf:phone, ??? ???, rdf:type, urn:mobile ???, form:bind, foaf_phone_mobile_3434535 And that will be enough to get you back to the target data. Wrap-up So, here are the takeways: Round tripping RDF to forms and back is tricky, not as simple as RDBMS backed data. When the RDF data looks like a hashmap where keys are non-unique you will have some work to do. With an RDBMS your psuedo excel for a phone would just be one long row (as opposed to lots of little rows) so you'd be roundtripping based on a row key. Any RDF vocab that allows multiple values for the same property without support for further qualification on the data isn't going to give you enough information to roundtrip with a form. You'll want to do some kind of extra type annotation in that case. You can only really do the RDF type annotation trick sensibly if the value is itself a URI, as with the phone numbers shown here. If you are working with literals things will be more complicated. Anywhere you end up using a hashmap to manage bindings in the web tier, you can manage those bindings as more RDF those and thus keep your form engine code as generic as possible. RDF graphs being pretty much hashmaps on steroids....