=head1 NAME
XAO::DO::ImportMap::Sample -- sample Import Map
=head1 SYNOPSIS
None.
=head1 DESCRIPTION
This sample implementation of Import Map is supposed to serve as a
template for real import maps.
It works on the following XML files:
=cut
###############################################################################
package XAO::DO::ImportMap::Sample;
use strict;
use XAO::Utils;
use XAO::Objects;
use XML::DOM;
use Error;
use base XAO::Objects->load(objname => 'ImportMap::Base');
use vars qw($VERSION);
$VERSION=(0+sprintf('%u.%03u',(q$Id: Sample.pm,v 1.2 2005/01/14 02:08:06 am Exp $ =~ /\s(\d+)\.(\d+)\s/))) || die "Bad VERSION";
###############################################################################
use constant MANUFACTURER => 'Sample Mfr';
###############################################################################
sub check_category_map ($$) {
my $self=shift;
my $cmap=shift;
if(!scalar($cmap->keys)) {
dprint "Populating category map";
my $c=$cmap->get_new();
$c->put(src_cat => 'foos');
$c->put(dst_cat => 'Tools::Foo');
$cmap->put($c);
$c->put(src_cat => 'bars::non-alcoholic');
$c->put(dst_cat => 'Food::Non-Alcoholic');
$cmap->put($c);
$c->put(src_cat => 'bars');
$c->put(dst_cat => 'Food::Drinks');
$cmap->put($c);
$c->put(src_cat => 'bars::non-alcoholic');
$c->put(dst_cat => 'Food::Drinks');
$cmap->put($c);
}
}
###############################################################################
sub map_xml_categories ($$$) {
my $self=shift;
my $xmlcont=shift;
my $catcont=shift;
my $catmap=shift;
##
# Preparing parser
#
my $parser=XML::DOM::Parser->new() ||
throw Error::Simple "Can't create XML::DOM parser";
##
# Doing two passes, first we collect categories into a hash and then
# we translate and store them.
#
my %cats;
my $doc;
foreach my $id (@{$xmlcont->search('type','eq','category')}) {
my $obj=$xmlcont->get($id);
$doc=$parser->parse($obj->get('value')) ||
throw Error::Simple ref($self)."::map_xml_categories - Can't parse category XML ($id)";
my $catdesc=$doc->getDocumentElement();
$catdesc->getNodeName() eq 'catdesc' ||
throw Error::Simple "Root node is not a ($id)";
my $attrmap=$catdesc->getAttributes();
my %hash;
foreach my $attrname (qw(id parent_id name description image thumbnail)) {
$hash{$attrname}=$self->xattr($attrmap,$attrname);
}
if(exists($cats{$hash{id}})) {
throw Error::Simple "This category ID was already used ($id)";
}
$cats{$hash{id}}=\%hash;
}
continue {
$doc->dispose() if $doc;
}
return $self->store_categories_hash($catcont,\%cats,$catmap);
}
###############################################################################
sub map_xml_products ($$$$) {
my $self=shift;
my $catalog=shift || throw Error::Simple ref($self)."::map_xml_products - no catalog given";;
my $prefix=shift || throw Error::Simple ref($self)."::map_xml_products - no prefix given";;
my $xmlcont=shift || throw Error::Simple ref($self)."::map_xml_products - no RawXML container given";
my $prodcont=shift || throw Error::Simple ref($self)."::map_xml_products - no Products container given";;
my $catmap=shift || throw Error::Simple ref($self)."::map_xml_products - no category map given";;
##
# Preparing parser
#
my $parser=XML::DOM::Parser->new() ||
throw Error::Simple "Can't create XML::DOM parser";
my $source_ref=$catalog->container_key || 'unknown';
my $source_seq=$catalog->get('source_seq') || 0;
$catalog->put(source_seq => ++$source_seq);
my $doc;
foreach my $objid (@{$xmlcont->search('type','eq','product')}) {
my $obj=$xmlcont->get($objid);
$doc=$parser->parse($obj->get('value')) ||
throw Error::Simple "Can't parse product XML ($objid)";
my $pdesc=$doc->getDocumentElement();
$pdesc->getNodeName() eq 'product' ||
throw Error::Simple "Root node is not a ($objid)";
##
# Scanning categories
#
my %cats;
foreach my $node ($pdesc->getElementsByTagName('category')) {
my $attrmap=$node->getAttributes();
my $id=$self->xattr($attrmap,'id');
if(!$id) {
eprint "No category ID is in one of the categories at $objid";
}
else {
my $list=$catmap->{$id};
if(!$list) {
eprint "Unknown category used in $objid";
}
else {
@cats{@{$list}}=@{$list};
}
}
}
my @cats=keys %cats; # making category IDs unique
undef %cats;
if(!@cats) {
eprint "Product $objid does not belong to any known category, skipping it";
next;
}
##
# Loading product description
#
my $attrmap=$pdesc->getAttributes();
my $id=$self->xattr($attrmap,'id');
if(!$id) {
eprint "No product ID at $objid";
next;
}
##
# Creating hash with product description to be passed into ID
# calculator
#
my %product=(
categories => \@cats,
description => $self->xattr($attrmap,'description'),
image_url => $self->xattr($attrmap,'image'),
manufacturer_id => $id,
manufacturer => MANUFACTURER,
name => $self->xattr($attrmap,'name'),
source_ref => $source_ref,
source_seq => $source_seq,
source_sku => $id,
thumbnail_url => $self->xattr($attrmap,'thumbnail'),
);
##
# Looking for matching SKU and taking suggestion for product
# ID. If there is no SKU then we ignore this product.
#
my $product_id=$self->product_id(\%product);
my $sku=$product{sku};
if(!$sku) {
dprint "Skipping product without known SKU - (id=$id)";
next;
}
##
# Looking for existing product with the same SKU. Ignoring
# suggested ID if found.
#
my $product_ids=$prodcont->search('sku','eq',$sku);
if(@{$product_ids}) {
$product_id=$product_ids->[0];
}
##
# Filling data into this detached object
#
my $pobj=$prodcont->get_new();
foreach my $fn (keys %product) {
next if $fn eq 'categories';
my $maxl=$pobj->describe($fn)->{maxlength};
my $value=$maxl ? substr($product{$fn},0,$maxl) : $product{$fn};
$pobj->put($fn => $value);
}
##
# Storing and reloading to get attached product reference.
#
if($product_id && $prodcont->exists($product_id)) {
my $curr_id=$prodcont->get($product_id)->get('source_sku');
if($id ne $curr_id) {
eprint "Cannot override products, current source_sku=$curr_id, new=$id, id=$product_id";
$product_id=undef;
}
}
if($product_id) {
$prodcont->put($product_id => $pobj);
}
else {
$product_id=$prodcont->put($pobj);
}
$pobj=$prodcont->get($product_id);
##
# Storing specs
#
my $specseq=1000;
my $specs=$pobj->get('Specification');
$specs->destroy();
my $spec_obj=$specs->get_new();
foreach my $node ($pdesc->getElementsByTagName('specification')) {
$attrmap=$node->getAttributes();
my $name=$self->xattr($attrmap,'name');
my $value=$self->xattr($attrmap,'value');
my $seq=sprintf('S%05u',$self->xattr($attrmap,'seq',$specseq++));
$spec_obj->put(param => $name);
$spec_obj->put(value => $value);
$specs->put($seq => $spec_obj);
}
##
# Now storing/updating categories
#
my $prod_cats=$pobj->get('Categories');
$prod_cats->destroy();
my $cat_obj=$prod_cats->get_new();
foreach my $cat (@cats) {
$prod_cats->put($cat => $cat_obj);
}
}
continue {
$doc->dispose() if $doc;
}
}
1;
__END__
=head1 AUTHORS
Copyright (c) 2005 Andrew Maltsev
Copyright (c) 2001-2004 Andrew Maltsev, XAO Inc.
-- http://ejelta.com/xao/