Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Wednesday January 23, 2008
05:16 AM

Bermuda XML

[ #35465 ]

For those who aren't familiar with Bermuda, it's an object serialization framework. Just write YAML config files (called "islands") and it writes the Perl code and the XML generation code. Eventually other output formats will be supported, along with RELAX NG generation and prebuilt test suites that you can drop your own fixtures into.

I went home last night and continued Bermuda work. I was planning on just relaxing, but I knew I probably won't have time to touch it again until next week.

Much of yesterday was spent paying off technical debt. I had spent a lot of "exploring" how to build Bermuda, but this meant that instead of passing around objects internally, I was passing around arbitrary data structures that were evolving along with my understanding. Now that I better understand those data structures, I'm slowly pulling them out and replacing them with proper objects. The code is becoming much cleaner, it's easier to use, and I get proper up-front validation.

So far, I can generate decent XML:

<?xml version="1.0" encoding="utf-8"?>
<address_book version="3" hard-coded="this is from YAML">
  <card revision="3" href="http://www.example.com/">
    <name some_attr="foo">John Smith</name>
    <email>js@example.com</email>
    <email>js2@example.com</email>
    <phone>111</phone>
    <phone>222</phone>
    <active>yes</active>
  </card>
</address_book>

And the island file is pretty simple:

---
package: My::AddressBook
island: address_book
attributes:
  version:
    type: positiveInteger
  hard-coded:
    data: 'this is from YAML'
elements:
  - card*
  - island: card
    method: cards

Note that the "card" element is a separate island, making it easy to organize things.

The only thing I find really annoying about this is that the "elements" are an even-sized list designed to simulate an ordered hash. YAML doesn't really support the idea of an array of pairs or ordered hashes, so I'm relying on the even-sized list. Here it is from the card island:

elements:
  - name
  - type: string
    attributes:
        some_attr:
            method: dummy_attribute
  - email*
  - type: string
  - phone+
  - method: phone_numbers
    type: string
  - active
  - data: yes

Can you tell at a glance if that is wrong? I can't and it's the format I designed! Each "even" element is a key and each "odd" element is the value (the element description). I'll be modifying the Bermuda::YAML parser to validate things like this, but for right now, it's a tiny annoyance. I'm just pleased with how well it's going.

Oh, and here's all it takes to render XML for any object you want to throw at it:

sub render {
    my ( $self, $island ) = @_;
    my $xml = XML::LibXML::Document->new( "1.0", "utf-8" );
    my $root = $xml->createElement( $island->name );
    $self->_render( $island, $xml, $root );
    $xml->setDocumentElement($root);
    return $xml->toString;
}

sub _render {
    my ( $self, $island, $xml, $root ) = @_;

    foreach my $attr ( $island->attributes ) {
        $root->setAttribute( $attr, $attr->value );
    }

    foreach my $element ( $data->elements } ) {
        my $node = $xml->createElement( $element->name );
        if ( $element->is_island ) {
            $self->_render( $element, $xml, $node );
            $root->addChild($node);
        }
        else {
            if ( my @attrs = $element->attributes ) {
                foreach my $attr ( @attrs ) {
                    $node->setAttribute($attr, $attr->value);
                }
            }
            $node->addChild( $xml->createTextNode( $element->value ) );
            $root->addChild($node);
        }
    }
    return $xml;
}

Not perfect, but not bad. Needs a bit of cleanup. I'm just disappointed that I won't have much time to work on it for a while.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Would you be less annoyed by a list of single-key hashes?

    elements:
      - name:
          type: string
          attributes:
              some_attr:
                  method: dummy_attribute
      - 'email*': { type: string }
      - 'phone+':
          method: phone_numbers
          type: string
      - active: { data: yes }
    • I like that. I do think it's clearer than what I had, but the existence of a hash implies that you can have multiple key/value pairs. Still, I don't think that's an expectation violation since these are island files with .bmd extensions and that means people should know they will need to read the docs.

  • Color me stupid, but what's wrong with it? Or, put another way, what structure are you trying to express?
    • What's wrong with what? If you mean the even-sized list, that should actually be an ordered list of pairs. That's something which Perl 6 can express, but not Perl 5 (at least, not cleanly). As a result, I need an even-sized list in the correct format (which sucks), or a list of hashes, each of which only has one key/value pair. I expect I'll go with the latter.

      Or were you referring to something else?

      • I'm unable to envision the structure you're trying to express. I don't understand how the XML and the two YAML snippets relate to each other.

        Some of the assertions confuse me because they seem to be wrong. Like "YAML doesn't really support the idea of an array of pairs or ordered hashes". They address this specifically in the spec [yaml.org]. Wouldn't an array of pairs be:

            - key:   value
            - this:  that
            - up:    down

        And why does it need to be ordered