Search Icon, Magnifying Glass

Marmanold.com

Graduation Cap Heart Question Mark Magnifying Glass

XML::Compile with an Extension Namespace

Starting this May, mortgage folk are going to be required to send Freddie and Fannie data including additional data points in ULDD phase 3 extension. At face value, adding these additional data points shouldn’t be a big deal at all. However, the legacy code I’m maintaining used XML::Compile to generate code. For various and sondry reasons — which I will not go into here — XML::Compile in the code I’m maintaining was in a place where it was extremely difficult to add XML elements that weren’t included in the original base Mismo 3.0 namespace.

If you, too, are stuck with a Perl hash structure marshalled into XML by XML::Compile and need to add elements in an extension namespace, I have good new for you. Using LibXML you can manually insert XML nodes from the extension namespace into your Perl hash object and XML::Compile will correctly marshall the structure into valid XML.

use warnings;
use strict;

#...

use XML::Compile::Schema;
use XML::Compile::Util qw/pack_type/;
use XML::LibXML;
use File::Slurp;

my @specs  = ('MISMO_3_0.xsd', 'xlink.xsd', 'ULDD_Phase_3_Extension.xsd');
my $schema = XML::Compile::Schema->new( \@specs, ( element_form_default => 'qualified' ) );
my $writer  = $schema->compile( WRITER => pack_type( 'http://www.mismo.org/residential/2009/schemas', 'MESSAGE' ), use_default_namespace => 0 );

my $uldd_other = create_xml_node("OTHER");
my $uldd_loan_identifier_extension = create_xml_node("LOAN_IDENTIFIER_EXTENSION");
my $uldd_loanidentifier = create_xml_element($d, "LoanIdentifier");
my $uldd_loanidentifiertype = create_xml_element($d, "LoanIdentifierType");

$uldd_loan_identifier_extension->appendChild($uldd_loanidentifier);
$uldd_loan_identifier_extension->appendChild($uldd_loanidentifiertype);
$uldd_other->appendChild($uldd_loan_identifier_extension);

my $xml_data = {
    #...
    LOAN_IDENTIFIERS => {
                LOAN_IDENTIFIER => [
                    #...
                    {EXTENSION => {
                        pack_type('http://www.datamodelextension.org/Schema/ULDD', 'OTHER') => $uldd_other,
                    },},
                ],
            },
    #...
};

my $doc = XML::LibXML::Document->new( '1.0', 'UTF-8' );
my $xml = $writer->( $doc, $xml_data );

$xml->setAttribute('xmlns:ULDD', 'http://www.datamodelextension.org/Schema/ULDD');
$doc->setDocumentElement($xml);

$xml = $doc->toString(1);
write_file( $filename, $xml );

sub create_xml_node {
    my ( $node_name ) = @_;

    my $node = XML::LibXML::Element->new($node_name);
    $node->setNamespace("http://www.datamodelextension.org/Schema/ULDD", "ULDD");

    return $node;
}

sub create_xml_element {
    my ( $d, $node_name ) = @_;

    my $node = XML::LibXML::Element->new($node_name);
    $node->setNamespace("http://www.datamodelextension.org/Schema/ULDD", "ULDD");

    if (exists($d->{$node_name}) && defined($d->{$node_name})) {
        $node->appendText($d->{$node_name});
        return $node;
    }

    return undef;
}

As you can see, this isn’t all too complicated. You use pack_type to let XML::Compile know about the extension namespace and then you basically build your own XML strucuture using LibXML.