NAME
PRANG::Graph - XML mapping by peppering Moose attributes
SYNOPSIS
# declaring a /language/
package My::XML::Language;
use Moose;
use PRANG::Graph;
sub xmlns { "some:urn" }
sub root_element { "Root" }
with 'PRANG::Graph';
has_element "data" =>
is => "ro",
isa => "My::XML::Language::Node",
;
# declaring a /node/ in a language
package My::XML::Language::Node;
use Moose;
use PRANG::Graph;
has_attr "count" =>
is => "ro",
isa => "Num",
;
has_element "text" =>
is => "ro",
isa => "Str",
xml_nodeName => "",
;
package main;
# example document for the above.
my $xml = q[<Root xmlns="some:urn"><data count="2">blah</data></Root>];
# loading XML to data structures
my $parsed = My::XML::Language->parse($xml);
# alternatives
$parsed = My::XML::Language->parse_file($filename);
$parsed = My::XML::Language->parse_fh($fh);
# converting back to XML
print $parsed->to_xml;
DESCRIPTION
PRANG::Graph allows you to mark attributes on your Moose classes as corresponding to XML attributes and child elements. This allows your class structure to function as an XML graph (a generalized form of an specification for the shape of an XML document; ie, what nodes and attributes are allowed at which point).
PRANG::Graph for document types
If a class implements a document type, that is, it is a valid root node for your language, it must both use
and implement the PRANG::Graph
role, and implement the required functions xmlns
and root_element
;
package XML::Language;
use Moose;
use PRANG::Graph;
sub xmlns { }
sub root_element { "rootNode" }
with 'PRANG::Graph';
If no URL is returned by the xmlns
function, XML namespaces are not permitted in the input documents.
PRANG::Graph for element types
If a class implements an element, that is, a node which appears somewhere other than the root node of your language, it must use
the PRANG::Graph
package. Well, actually, it must apply the PRANG class trait, but using the package will also define the useful functions has_attr
and has_element
, so most users will want that.
The minimum is;
package XML::Language::SomeElement;
use PRANG::Graph;
Note, the name of the node is not defined in the class itself, it is defined in the class which includes it, using the has_element
method. See PRANG::Graph::Meta::Element for more information.
PRANG::Graph for multi-root document types
If your language has multiple valid root elements, then you must define one document type for each valid root element. These must all implement a particular role, which should bundle the PRANG::Graph
role. The common role should not define root_element
, but probably should define xmlns
in most cases:
eg,
package XML::Language::Family;
use Moose::Role;
sub xmlns { }
with 'PRANG::Graph';
package XML::Language::One;
use Moose;
use PRANG::Graph;
sub root_element { "one" }
with 'XML::Language::Family';
package XML::Language::Two;
use Moose;
use PRANG::Graph;
sub root_element { "two" }
with 'XML::Language::Family';
PRANG::Graph for plug-in element types
Normally, the details on the node name of elements is in the class which includes those elements, not the target classes. However, it is also possible to refer to roles instead of classes. The first time the parser encounters this, it sees which loaded classes implement that role, and then builds the map from element name to class.
The classes should implement the PRANG::Graph
role, effectively defining a document type.
The effect of specifying a role as a type is to immediate search all loaded packages to see which consume the specified role.
Given the example in the previous section, if you used:
has_element 'some_attr' =>
is => "ro",
isa => "XML::Language::Family",
;
It would be the same as:
has_element 'some_attr' =>
is => "ro",
isa => "XML::Language::One|XML::Language::Two",
xml_nodeName => {
one => "XML::Language::One",
two => "XML::Language::Two",
},
;
Otherwise, the requirements are the same as for regular element definition as described in PRANG::Graph::Meta::Element. In particular, two types cannot share the same xmlns
and root_element
; that would be ambiguous.
EXPORTS
These exports are delivered to the class which says use PRANG::Graph;
has_attr
This is the same as declaring an attribute using the regular Moose has
keyword, but adds the PRANG::Attr
trait, declared in PRANG::Graph::Meta::Attr - the attribute will behave just like a regular Moose attribute, but the marshalling machinery will convert it to and from a particular XML attribute (or even multiple attributes). See PRANG::Graph::Meta::Attr for more information.
has_element
Same as has_attr
, except it adds the PRANG::Element
trait, indicating to the marshalling machinery to emit an XML node or sequence of nodes. See PRANG::Graph::Meta::Element.
METHODS
These methods are defined in, or required classes which implement the PRANG::Graph
role. In general, that means they are a document type.
parse($class: Str $xml) returns Object
Parse an XML string according to the PRANG Graph and return the built object. Throws exceptions on error.
By example, this is:
my $object = $class->parse($xml);
to_xml(PRANG::Graph $object: Int $format = 0) returns Str
Converts an object to an XML string. The returned XML will include the XML declaration and so on. Output will be indented by LibXML2 if the format
parameter is set to 1. The default is 0 (do not indent). See "toString" in XML::LibXML::Document for other valid values.
By example, this is:
my $xml = $object->to_xml;
xmlns(Moose::Meta::Class $class:) returns Maybe[Str]
This is a required class method which returns the XML namespace of this document type. This is used for emitting, and when parsing the input namespace must generally be either unset or match this XML namespace.
If you are not using namespaces, just define the method in your class, and return a false value.
root_element(Moose::Meta::Class $class:) returns Str
This is a required class method which returns the XML name of the element which corresponds to this document type.
HOW IT WORKS
These details are not important for regular use of PRANG, however if you can understand this you will grok the module much more quickly.
This class applies a trait to your classes' metaclass. This means, that when you use PRANG::Graph
, there is an implied;
use Moose -traits => ["PRANG"];
Which is something like;
PRANG::Graph::Meta::Class->meta->apply(__PACKAGE__->meta);
That sets up the metaclass to be capable of being used by the marshalling machinery. This machinery expects Moose attributes which have the PRANG::Element
or PRANG::Attr
traits applied to connect XML attributes and elements to object attributes. These are in turn implemented by the PRANG::Graph::Meta::Attr and PRANG::Graph::Meta::Element classes.
Applying the PRANG::Graph role happens separately, and delivers a separate set of super-powers. It is roughly equivalent to;
PRANG::Graph->meta->apply(__PACKAGE__);
So, the key difference between these two aspects are the source package, and the destination meta-object; in one, it is the class, in the other, the metaclass.
SEE ALSO
PRANG, PRANG::Graph::Meta::Class, PRANG::Graph::Meta::Attr, PRANG::Graph::Meta::Element, PRANG::Graph::Node
AUTHOR AND LICENCE
Development commissioned by NZ Registry Services, and carried out by Catalyst IT - http://www.catalyst.net.nz/
Copyright 2009, 2010, NZ Registry Services. This module is licensed under the Artistic License v2.0, which permits relicensing under other Free Software licenses.