# RDF::RDFa reader/writer

[RDFa][RDFa 1.1 Core] parser for RDF.rb.

## DESCRIPTION
RDF::RDFa is an RDFa reader and writer for Ruby using the [RDF.rb][RDF.rb] library suite.

## FEATURES
RDF::RDFa parses [RDFa][RDFa 1.1 Core] into statements or triples.

* Fully compliant RDFa 1.1 parser.
* Template-based Writer to generate XHTML+RDFa.
  * Writer uses user-replacable [Haml][Haml]-based templates to generate RDFa.
* Uses Nokogiri for parsing HTML/SVG
* [RDFa tests][RDFa-test-suite] use SPARQL for most tests due to Rasqal limitations. Other tests compare directly against N-triples.

Install with 'gem install rdf-rdfa'

## Usage

### Reading RDF data in the RDFa format

    RDF::RDFa::Reader.open("etc/foaf.html") do |reader|
      reader.each_statement do |statement|
        puts statement.inspect
      end
    end

### Writing RDF data using the XHTML+RDFa format

    require 'rdf/rdfa'
    
    RDF::RDFa::Writer.open("hello.html") do |writer|
      writer << RDF::Graph.new do |graph|
        graph << [:hello, RDF::DC.title, "Hello, world!"]
      end
    end

Note that prefixes may be chained between Reader and Writer, so that the Writer will
use the same prefix definitions found during parsing:

    prefixes = {}
    graph = RDF::Graph.load("etc/foaf.html", :prefixes => prefixes)
    puts graph.dump(:rdfa, :prefixes => prefixes)
    
### Template-based Writer
The RDFa writer uses [Haml][Haml] templates for code generation. This allows fully
customizable RDFa output in a variety of host languages.
The [default template]({RDF::RDFa::Writer::DEFAULT_HAML}) generates human readable HTML5
output. A [minimal template]({RDF::RDFa::Writer::MIN_HAML}) generates HTML, which is not
intended for human consumption.

To specify an alternative Haml template, consider the following:

    require 'rdf/rdfa'
    
    RDF::RDFa::Writer.buffer(:haml => RDF::RDFa::Writer::MIN_HAML) << graph

The template hash defines four Haml templates:

*   _doc_: Document Template, takes an ordered list of _subject_s and yields each one to be rendered.
    Described further in {RDF::RDFa::Writer#render_document}.

        !!! XML
        !!! 5
        %html{:xmlns => "http://www.w3.org/1999/xhtml", :lang => lang, :profile => profile, :prefix => prefix}
          - if base || title
            %head
              - if base
                %base{:href => base}
              - if title
                %title= title
          %body
            - subjects.each do |subject|
              != yield(subject)

    This template takes locals _lang_, _profile_, _prefix_, _base_, _title_ in addition to _subjects_
    to create output similar to the following:
      
        <!DOCTYPE html>
        <html prefix='xhv: http://www.w3.org/1999/xhtml/vocab#' xmlns='http://www.w3.org/1999/xhtml'>
          <head>
            <base href="http://example/">
            <title>Document Title</title>
          </head>
          <body>
            ...
          </body>
        </html>
      
    Options passed to the Writer are used to supply _lang_, _profile_ and _base_ locals.
    _prefix_ is generated based upon prefixes found from default or supplied profiles, as well
    as those provided by a previous Reader. _title_ is taken from the first top-level subject
    having an appropriate title property (as defined by the _heading_predicates_ option).

*   _subject_: Subject Template, take a _subject_ and an order list of _predicate_s and yields
    each _predicate_ to be rendered. Described further in {RDF::RDFa::Writer#render_subject}.
    
        - if element == :li
          %li{:about => get_curie(subject), :typeof => typeof}
            - if typeof
              %span.type!= typeof
            - predicates.each do |predicate|
              != yield(predicate)
        - elsif rel && typeof
          %div{:rel => get_curie(rel)}
            %div{:about => get_curie(subject), :typeof => typeof}
              %span.type!= typeof
              - predicates.each do |predicate|
                != yield(predicate)
        - elsif rel
          %div{:rel => get_curie(rel), :resource => get_curie(subject)}
            - predicates.each do |predicate|
              != yield(predicate)
        - else
          %div{:about => get_curie(subject), :typeof => typeof}
            - if typeof
              %span.type!= typeof
            - predicates.each do |predicate|
              != yield(predicate)
    
    The template takes locals _rel_ and _typeof_ in addition to _predicates_ and _subject_ to
    create output similar to the following:
    
        <div about="http://example/">
          ...
        </div>

    Note that if _typeof_ is defined, in this template, it will generate a textual description.
    
*   _property\_value_: Property Value Template, used for predicates having a single value; takes
    a _predicate_, and a single-valued Array of _objects_. Described further in {RDF::RDFa::Writer#render\_property}.
    
        - object = objects.first
        - if heading_predicates.include?(predicate) && object.literal?
          %h1{:property => get_curie(predicate), :content => get_content(object), :lang => get_lang(object), :datatype => get_dt_curie(object)}&= get_value(object)
        - else
          %div.property
            %span.label
              = get_predicate_name(predicate)
            - if res = yield(object)
              != res
            - elsif object.node?
              %span{:resource => get_curie(object), :rel => get_curie(predicate)}= get_curie(object)
            - elsif object.uri?
              %a{:href => object.to_s, :rel => get_curie(predicate)}= object.to_s
            - elsif object.datatype == RDF.XMLLiteral
              %span{:property => get_curie(predicate), :lang => get_lang(object), :datatype => get_dt_curie(object)}<!= get_value(object)
            - else
              %span{:property => get_curie(predicate), :content => get_content(object), :lang => get_lang(object), :datatype => get_dt_curie(object)}&= get_value(object)
   
    In addition to _predicate_ and _objects_, the template takes locals _property_ and/or _rel_, which are
    copies of _predicate_ and indicate use in the @property or @rel attributes. Either or both may be
    specified, as the conditions dictate.

    Also, if the predicate is identified as a _heading predicate_ (via _:heading\_predicates_ option),
    it will generate a heading element, and may use the value as the document title.

    Each _object_ is yielded to the calling block, and the result is rendered, unless nil.
    Otherwise, rendering depends on the type of _object_. This is useful for recursive document
    descriptions.

    Creates output similar to the following:
    
        <div class='property'>
          <span class='label'>
            xhv:alternate
          </span>
          <a href='http://rdfa.info/feed/' rel='xhv:alternate'>http://rdfa.info/feed/</a>
        </div>
    
    Note the use of methods defined in {RDF::RDFa::Writer} useful in rendering the output.
    
*   _property\_values_: Similar to _property\_value_, but for predicates having more than one value.
    Locals are identical to _property\_values_, but _objects_ is expected to have more than one value.
    
        %div.property
          %span.label
            = get_predicate_name(predicate)
          %ul{:rel => (get_curie(rel) if rel), :property => (get_curie(property) if property)}
            - objects.each do |object|
              - if res = yield(object)
                != res
              - elsif object.node?
                %li{:resource => get_curie(object)}= get_curie(object)
              - elsif object.uri?
                %li
                  %a{:href => object.to_s}= object.to_s
              - elsif object.datatype == RDF.XMLLiteral
                %li{:lang => get_lang(object), :datatype => get_curie(object.datatype)}<!= get_value(object)
              - else
                %li{:content => get_content(object), :lang => get_lang(object), :datatype => get_dt_curie(object)}&= get_value(object)
  
    In this case, and unordered list is used for output. Creates output similar to the following:
    
        <div class='property'>
          <span class='label'>
            xhv:bookmark
          </span>
          <ul rel='xhv:bookmark'>
            <li>
              <a href='http://rdfa.info/2009/12/12/oreilly-catalog-uses-rdfa/'>
                http://rdfa.info/2009/12/12/oreilly-catalog-uses-rdfa/
              </a>
            </li>
              <a href='http://rdfa.info/2010/05/31/new-rdfa-checker/'>
                http://rdfa.info/2010/05/31/new-rdfa-checker/
              </a>
            </li>
          </ul>
        </div>
    If _property\_values_ does not exist, repeated values will be replecated
    using _property\_value_.
* Type-specific templates.
  To simplify generation of different output types, the
  template may contain a elements indexed by a URI. When a subject with an rdf:type
  matching that URI is found, subsequent Haml definitions will be taken from
  the associated Hash. For example:
  
    {
      :document => "...",
      :subject => "...",
      :property\_value => "...",
      :property\_values => "...",
      RDF::URI("http://schema.org/Person") => {
        :subject => "...",
        :property\_value => "...",
        :property\_values => "...",
      }
    }

## Dependencies
* [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.3.1)
* [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.3.3)
* [Haml](https://rubygems.org/gems/haml) (>= 3.0.0)

## Documentation
Full documentation available on [RubyForge](http://rdf.rubyforge.org/rdfa)

### Principle Classes
* {RDF::RDFa::Format}
  * {RDF::RDFa::HTML}
    Asserts :html format, text/html mime-type and .html file extension.
  * {RDF::RDFa::XHTML}
    Asserts :html format, application/xhtml+xml mime-type and .xhtml file extension.
  * {RDF::RDFa::SVG}
    Asserts :svg format, image/svg+xml mime-type and .svg file extension.
* {RDF::RDFa::Reader}
* {RDF::RDFa::Profile}
* {RDF::RDFa::Writer}

### Additional vocabularies
* {RDF::PTR}
* {RDF::RDFA}
* {RDF::XHV}
* {RDF::XML}
* {RDF::XSI}

## TODO
* Add support for LibXML and REXML bindings, and use the best available
* Consider a SAX-based parser for improved performance

## Resources
* [RDF.rb][RDF.rb]
* [Distiller](http://rdf.greggkellogg.net/distiller)
* [Documentation](http://rdf.rubyforge.org/rdfa)
* [History](file:file.History.html)
* [RDFa 1.1 Core][RDFa 1.1 Core]
* [XHTML+RDFa 1.1][XHTML+RDFa 1.1]
* [RDFa-test-suite](http://rdfa.digitalbazaar.com/test-suite/              "RDFa test suite")

## Author
* [Gregg Kellogg](http://github.com/gkellogg) - <http://kellogg-assoc.com/>

## Contributors
* [Nicholas Humfrey](http://github.com/njh)

## Contributing

* Do your best to adhere to the existing coding conventions and idioms.
* Don't use hard tabs, and don't leave trailing whitespace on any line.
* Do document every method you add using [YARD][] annotations. Read the
  [tutorial][YARD-GS] or just look at the existing code for examples.
* Don't touch the `.gemspec`, `VERSION` or `AUTHORS` files. If you need to
  change them, do so on your private branch only.
* Do feel free to add yourself to the `CREDITS` file and the corresponding
  list in the the `README`. Alphabetical order applies.
* Do note that in order for us to merge any non-trivial changes (as a rule
  of thumb, additions larger than about 15 lines of code), we need an
  explicit [public domain dedication][PDD] on record from you.

## License

This is free and unencumbered public domain software. For more information,
see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.

## FEEDBACK

* gregg@kellogg-assoc.com
* <http://rubygems.org/rdf-rdfa>
* <http://github.com/gkellogg/rdf-rdfa>
* <http://lists.w3.org/Archives/Public/public-rdf-ruby/>

[RDF.rb]:           http://rdf.rubyforge.org/
[YARD]:             http://yardoc.org/
[YARD-GS]:          http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
[PDD]:              http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
[RDFa 1.1 Core]:    http://www.w3.org/TR/2011/WD-rdfa-core-20110331/     "RDFa 1.1 Core"
[XHTML+RDFa 1.1]:   http://www.w3.org/TR/2011/WD-xhtml-rdfa-20110331/   "XHTML+RDFa 1.1"
[RDFa-test-suite]:  http://rdfa.digitalbazaar.com/test-suite/           "RDFa test suite"
[Haml]:             http://haml-lang.com/