Search Icon, Magnifying Glass

Marmanold.com

Graduation Cap Heart Question Mark Magnifying Glass

XML::Compile with an Extension Namespace

perl xml schema xsd mismo uldd mortgage

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.