-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
XMLInvoice: gültige namespaces aus der xml holen ... #419
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,7 @@ to discover the metadata keys guaranteed to be present. | |
=cut | ||
|
||
sub data_keys { | ||
my $self = shift; | ||
my @keys = ( | ||
'currency', # The bill's currency, such as "EUR" | ||
'direct_debit', # Boolean: whether the bill will get paid by direct debit (1) or not (0) | ||
|
@@ -85,6 +86,7 @@ to discover the metadata keys guaranteed to be present. | |
=cut | ||
|
||
sub item_keys { | ||
my $self = shift; | ||
my @keys = ( | ||
'currency', | ||
'description', | ||
|
@@ -144,6 +146,17 @@ sub check_signature { | |
die "Children of $self must implement a check_signature() method returning 1 for supported XML, 0 for unsupported XML."; | ||
} | ||
|
||
=item namespaces($dom) | ||
|
||
This static method takes a DOM object and returns an ArrayofHashes[ data => localname ]. C<SL::XMLInvoice> uses this method to determine which ns is valid for wich data. All child classes must implement this method. | ||
|
||
=cut | ||
|
||
sub namespaces { | ||
my $self = shift; | ||
die "Children of $self must implement a namespaces() method returning an aoh with the namespaces"; | ||
} | ||
|
||
=item supported() | ||
|
||
This static method returns an array of free-form strings describing XML invoice | ||
|
@@ -227,6 +240,7 @@ C<item_keys>. Omitting this method from a child class will cause an exception. | |
=head1 AUTHOR | ||
|
||
Johannes Grassler <[email protected]> | ||
Werner Hahn <[email protected]> | ||
|
||
=cut | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,6 @@ use warnings; | |
|
||
use parent qw(SL::XMLInvoice::Base); | ||
|
||
use constant ITEMS_XPATH => '//ram:IncludedSupplyChainTradeLineItem'; | ||
|
||
=head1 NAME | ||
|
||
SL::XMLInvoice::CrossIndustryDocument - XML parser for UN/CEFACT Cross Industry Document | ||
|
@@ -51,6 +49,7 @@ returned by the C<items()> method. | |
=head1 AUTHOR | ||
|
||
Johannes Grassler <[email protected]> | ||
Werner Hahn <[email protected]> | ||
|
||
=cut | ||
|
||
|
@@ -73,39 +72,75 @@ sub check_signature { | |
return 0; | ||
} | ||
|
||
sub namespaces { | ||
my ($self, $dom) = @_; | ||
my $rootnode = $dom->documentElement; | ||
my @nodes = $rootnode->findnodes('namespace::*'); | ||
my @namespaces = map {[ $_->getData, $_->getLocalName]} @nodes; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Das hier sieht falsch aus. Müsste auch ein hash zurückgegeben werden wie in der anderen Datei oder? |
||
return \@namespaces; | ||
} | ||
|
||
# XML XPath expressions for global metadata | ||
sub scalar_xpaths { | ||
my ($self) = @_; | ||
|
||
my $rsm = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'}; | ||
my $ram = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'}; | ||
my $udt = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'}; | ||
$ram .= ":" if $ram; | ||
$rsm .= ":" if $rsm; | ||
$udt .= ":" if $udt; | ||
|
||
return { | ||
currency => ['//ram:InvoiceCurrencyCode'], | ||
direct_debit => ['//ram:SpecifiedTradeSettlementPaymentMeans/ram:TypeCode'], | ||
duedate => ['//ram:DueDateDateTime/udt:DateTimeString', '//ram:EffectiveSpecifiedPeriod/ram:CompleteDateTime/udt:DateTimeString'], | ||
gross_total => ['//ram:DuePayableAmount'], | ||
iban => ['//ram:SpecifiedTradeSettlementPaymentMeans/ram:PayeePartyCreditorFinancialAccount/ram:IBANID'], | ||
invnumber => ['//rsm:HeaderExchangedDocument/ram:ID'], | ||
net_total => ['//ram:TaxBasisTotalAmount'], | ||
transdate => ['//ram:IssueDateTime/udt:DateTimeString'], | ||
taxnumber => ['//ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="FC"]'], | ||
type => ['//rsm:HeaderExchangedDocument/ram:TypeCode'], | ||
ustid => ['//ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="VA"]'], | ||
vendor_name => ['//ram:SellerTradeParty/ram:Name'], | ||
currency => ['//' . $ram . 'InvoiceCurrencyCode'], | ||
direct_debit => ['//' . $ram . 'SpecifiedTradeSettlementPaymentMeans/' . $ram . 'TypeCode'], | ||
duedate => ['//' . $ram . 'DueDateDateTime/' . $udt . 'DateTimeString', '//' . $ram . 'EffectiveSpecifiedPeriod/' . $ram . 'CompleteDateTime/' . $udt . 'DateTimeString'], | ||
gross_total => ['//' . $ram . 'DuePayableAmount'], | ||
iban => ['//' . $ram . 'SpecifiedTradeSettlementPaymentMeans/' . $ram . 'PayeePartyCreditorFinancialAccount/' . $ram . 'IBANID'], | ||
invnumber => ['//' . $rsm . 'HeaderExchangedDocument/' . $ram . 'ID'], | ||
net_total => ['//' . $ram . 'TaxBasisTotalAmount'], | ||
transdate => ['//' . $ram . 'IssueDateTime/' . $udt . 'DateTimeString'], | ||
taxnumber => ['//' . $ram . 'SellerTradeParty/' . $ram . 'SpecifiedTaxRegistration/' . $ram . 'ID[@schemeID="FC"]'], | ||
type => ['//' . $rsm . 'HeaderExchangedDocument/' . $ram . 'TypeCode'], | ||
ustid => ['//' . $ram . 'SellerTradeParty/' . $ram . 'SpecifiedTaxRegistration/' . $ram . 'ID[@schemeID="VA"]'], | ||
vendor_name => ['//' . $ram . 'SellerTradeParty/' . $ram . 'Name'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mein Beileid, dass Du den Kram so tippen musstest. Ich habe geschaut ob das irgendwie eleganter geht, habe aber auch nichts gefunden. LibXML unterstützt leider kein XPath 3.0, da hätte es eine Syntax zumindest für namespaces per url gegeben. Optionale namespaces sind aber anscheinend überhaupt nicht unterstützt. Ich habe aber auch nochmal im Zugferd Standard nachgeschaut, und wenn ich nicht blind bin, sind die namespaces nicht optional. Für mich wäre das also hier auch absolut okay, wenn das konsequent einen Fehler wirft wenn die 3 namespaces nicht gefunden werden. Ist aber kein Grund das nochmal anzufassen. |
||
}; | ||
} | ||
|
||
sub item_xpaths { | ||
my ($self) = @_; | ||
|
||
my $rsm = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'}; | ||
my $ram = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'}; | ||
my $udt = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'}; | ||
$ram .= ":" if $ram; | ||
$rsm .= ":" if $rsm; | ||
$udt .= ":" if $udt; | ||
|
||
return { | ||
'currency' => ['./ram:SpecifiedSupplyChainTradeAgreement/ram:GrossPriceProductTradePrice/ram:ChargeAmount[attribute::currencyID]', | ||
'./ram:SpecifiedSupplyChainTradeAgreement/ram:GrossPriceProductTradePrice/ram:BasisAmount'], | ||
'price' => ['./ram:SpecifiedSupplyChainTradeAgreement/ram:GrossPriceProductTradePrice/ram:ChargeAmount', | ||
'./ram:SpecifiedSupplyChainTradeAgreement/ram:GrossPriceProductTradePrice/ram:BasisAmount'], | ||
'description' => ['./ram:SpecifiedTradeProduct/ram:Name'], | ||
'quantity' => ['./ram:SpecifiedSupplyChainTradeDelivery/ram:BilledQuantity',], | ||
'subtotal' => ['./ram:SpecifiedSupplyChainTradeSettlement/ram:SpecifiedTradeSettlementMonetarySummation/ram:LineTotalAmount'], | ||
'tax_rate' => ['./ram:SpecifiedSupplyChainTradeSettlement/ram:ApplicableTradeTax/ram:ApplicablePercent'], | ||
'tax_scheme' => ['./ram:SpecifiedSupplyChainTradeSettlement/ram:ApplicableTradeTax/ram:TypeCode'], | ||
'vendor_partno' => ['./ram:SpecifiedTradeProduct/ram:SellerAssignedID'], | ||
'currency' => ['./' . $ram . ':SpecifiedSupplyChainTradeAgreement/' . $ram . ':GrossPriceProductTradePrice/' . $ram . ':ChargeAmount[attribute::currencyID]', | ||
'./' . $ram . ':SpecifiedSupplyChainTradeAgreement/' . $ram . ':GrossPriceProductTradePrice/' . $ram . ':BasisAmount'], | ||
'price' => ['./' . $ram . ':SpecifiedSupplyChainTradeAgreement/' . $ram . ':GrossPriceProductTradePrice/' . $ram . ':ChargeAmount', | ||
'./' . $ram . ':SpecifiedSupplyChainTradeAgreement/' . $ram . ':GrossPriceProductTradePrice/' . $ram . ':BasisAmount'], | ||
'description' => ['./' . $ram . ':SpecifiedTradeProduct/' . $ram . ':Name'], | ||
'quantity' => ['./' . $ram . ':SpecifiedSupplyChainTradeDelivery/' . $ram . ':BilledQuantity',], | ||
'subtotal' => ['./' . $ram . ':SpecifiedSupplyChainTradeSettlement/' . $ram . ':SpecifiedTradeSettlementMonetarySummation/' . $ram . ':LineTotalAmount'], | ||
'tax_rate' => ['./' . $ram . ':SpecifiedSupplyChainTradeSettlement/' . $ram . ':ApplicableTradeTax/' . $ram . ':ApplicablePercent'], | ||
'tax_scheme' => ['./' . $ram . ':SpecifiedSupplyChainTradeSettlement/' . $ram . ':ApplicableTradeTax/' . $ram . ':TypeCode'], | ||
'vendor_partno' => ['./' . $ram . ':SpecifiedTradeProduct/' . $ram . ':SellerAssignedID'], | ||
}; | ||
} | ||
|
||
sub items_xpath { | ||
my ($self) = @_; | ||
my $rsm = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'}; | ||
my $ram = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'}; | ||
my $udt = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'}; | ||
$ram .= ":" if $ram; | ||
$rsm .= ":" if $rsm; | ||
$udt .= ":" if $udt; | ||
return '//' . $ram . 'IncludedSupplyChainTradeLineItem'; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Das braucht nur den ram namespace - braucht die anderen beiden hier also nicht reinkopieren. Wenn Du das so oft kopierst, macht evtl eine Methode Sinn, die den namespace nachschlägt und wenn vorhanden mit |
||
|
||
# Metadata accessor method | ||
sub metadata { | ||
|
@@ -145,6 +180,9 @@ sub parse_xml { | |
$self->{_metadata} = {}; | ||
$self->{_items} = (); | ||
|
||
my $ram = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'}; | ||
$ram .= ":" if $ram; | ||
my $udt = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'}; | ||
# Retrieve scalar metadata from DOM | ||
foreach my $key ( keys %{$self->scalar_xpaths} ) { | ||
foreach my $xpath ( @{${$self->scalar_xpaths}{$key}} ) { | ||
|
@@ -154,6 +192,10 @@ sub parse_xml { | |
next; | ||
} | ||
my $value = $self->{dom}->findnodes($xpath); | ||
unless ($udt) { | ||
$value = $self->{dom}->findnodes('//' . $ram . 'DueDateDateTime','DateTimeString') if $key eq 'duedate'; | ||
$value = $self->{dom}->findnodes('//' . $ram . 'IssueDateTime','DateTimeString') if $key eq 'transdate'; | ||
} | ||
if ( $value ) { | ||
# Get rid of extraneous white space | ||
$value = $value->string_value; | ||
|
@@ -175,7 +217,7 @@ sub parse_xml { | |
my @items; | ||
$self->{_items} = \@items; | ||
|
||
foreach my $item ( $self->{dom}->findnodes(ITEMS_XPATH)) { | ||
foreach my $item ( $self->{dom}->findnodes($self->items_xpath)) { | ||
my %line_item; | ||
foreach my $key ( keys %{$self->item_xpaths} ) { | ||
foreach my $xpath ( @{${$self->item_xpaths}{$key}} ) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,6 @@ use warnings; | |
|
||
use parent qw(SL::XMLInvoice::Base); | ||
|
||
use constant ITEMS_XPATH => '//ram:IncludedSupplyChainTradeLineItem'; | ||
|
||
=head1 NAME | ||
|
||
|
@@ -51,6 +50,7 @@ returned by the C<items()> method. | |
=head1 AUTHOR | ||
|
||
Johannes Grassler <[email protected]> | ||
Werner Hahn <[email protected]> | ||
|
||
=cut | ||
|
||
|
@@ -73,37 +73,71 @@ sub check_signature { | |
return 0; | ||
} | ||
|
||
sub namespaces { | ||
my ($self, $dom) = @_; | ||
my $rootnode = $dom->documentElement; | ||
my @nodes = $rootnode->findnodes('namespace::*'); | ||
my %namespaces = map { $_->getData => $_->getLocalName} @nodes; | ||
return \%namespaces; | ||
} | ||
|
||
# XML XPath expressions for global metadata | ||
sub scalar_xpaths { | ||
my ($self) = @_; | ||
|
||
my $rsm = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'}; | ||
my $ram = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'}; | ||
my $udt = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'}; | ||
$ram .= ":" if $ram; | ||
$rsm .= ":" if $rsm; | ||
$udt .= ":" if $udt; | ||
|
||
return { | ||
currency => '//ram:InvoiceCurrencyCode', | ||
direct_debit => '//ram:SpecifiedTradeSettlementPaymentMeans/ram:TypeCode', | ||
duedate => '//ram:DueDateDateTime/udt:DateTimeString', | ||
gross_total => '//ram:DuePayableAmount', | ||
iban => '//ram:SpecifiedTradeSettlementPaymentMeans/ram:PayeePartyCreditorFinancialAccount/ram:IBANID', | ||
invnumber => '//rsm:ExchangedDocument/ram:ID', | ||
net_total => '//ram:SpecifiedTradeSettlementHeaderMonetarySummation' . '//ram:TaxBasisTotalAmount', | ||
transdate => '//ram:IssueDateTime/udt:DateTimeString', | ||
taxnumber => '//ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="FC"]', | ||
type => '//rsm:ExchangedDocument/ram:TypeCode', | ||
ustid => '//ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="VA"]', | ||
vendor_name => '//ram:SellerTradeParty/ram:Name', | ||
currency => '//' . $ram . 'InvoiceCurrencyCode', | ||
direct_debit => '//' . $ram . 'SpecifiedTradeSettlementPaymentMeans/' . $ram . 'TypeCode', | ||
duedate => '//' . $ram . 'DueDateDateTime/' . $udt . 'DateTimeString', | ||
gross_total => '//' . $ram . 'DuePayableAmount', | ||
iban => '//' . $ram . 'SpecifiedTradeSettlementPaymentMeans/' . $ram . 'PayeePartyCreditorFinancialAccount/' . $ram . 'IBANID', | ||
invnumber => '//' . $rsm . 'ExchangedDocument/' . $ram . 'ID', | ||
net_total => '//' . $ram . 'SpecifiedTradeSettlementHeaderMonetarySummation' . '//' . $ram . 'TaxBasisTotalAmount', | ||
transdate => '//' . $ram . 'IssueDateTime/' . $udt . 'DateTimeString', | ||
taxnumber => '//' . $ram . 'SellerTradeParty/' . $ram . 'SpecifiedTaxRegistration/' . $ram . 'ID[@schemeID="FC"]', | ||
type => '//' . $rsm . 'ExchangedDocument/' . $ram . 'TypeCode', | ||
ustid => '//' . $ram . 'SellerTradeParty/' . $ram . 'SpecifiedTaxRegistration/' . $ram . 'ID[@schemeID="VA"]', | ||
vendor_name => '//' . $ram . 'SellerTradeParty/' . $ram . 'Name', | ||
}; | ||
} | ||
|
||
sub item_xpaths { | ||
my ($self) = @_; | ||
my $rsm = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'}; | ||
my $ram = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'}; | ||
my $udt = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'}; | ||
$ram .= ":" if $ram; | ||
$rsm .= ":" if $rsm; | ||
$udt .= ":" if $udt; | ||
return { | ||
'currency' => undef, # Only global currency in CrossIndustryInvoice | ||
'price' => './ram:SpecifiedLineTradeAgreement/ram:NetPriceProductTradePrice', | ||
'description' => './ram:SpecifiedTradeProduct/ram:Name', | ||
'quantity' => './ram:SpecifiedLineTradeDelivery/ram:BilledQuantity', | ||
'subtotal' => './ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeSettlementLineMonetarySummation/ram:LineTotalAmount', | ||
'tax_rate' => './ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent', | ||
'tax_scheme' => './ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:TypeCode', | ||
'vendor_partno' => './ram:SpecifiedTradeProduct/ram:SellerAssignedID', | ||
'currency' => undef, # Only global currency in CrossIndustryInvoice | ||
'price' => './' . $ram . 'SpecifiedLineTradeAgreement/' . $ram . 'NetPriceProductTradePrice', | ||
'description' => './' . $ram . 'SpecifiedTradeProduct/' . $ram . 'Name', | ||
'quantity' => './' . $ram . 'SpecifiedLineTradeDelivery/' . $ram . 'BilledQuantity', | ||
'subtotal' => './' . $ram . 'SpecifiedLineTradeSettlement/' . $ram . 'SpecifiedTradeSettlementLineMonetarySummation/' . $ram . 'LineTotalAmount', | ||
'tax_rate' => './' . $ram . 'SpecifiedLineTradeSettlement/' . $ram . 'ApplicableTradeTax/' . $ram . 'RateApplicablePercent', | ||
'tax_scheme' => './' . $ram . 'SpecifiedLineTradeSettlement/' . $ram . 'ApplicableTradeTax/' . $ram . 'TypeCode', | ||
'vendor_partno' => './' . $ram . 'SpecifiedTradeProduct/' . $ram . 'SellerAssignedID', | ||
}; | ||
} | ||
|
||
sub items_xpath { | ||
my ($self) = @_; | ||
my $rsm = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'}; | ||
my $ram = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'}; | ||
my $udt = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'}; | ||
$ram .= ":" if $ram; | ||
$rsm .= ":" if $rsm; | ||
$udt .= ":" if $udt; | ||
return '//' . $ram . 'IncludedSupplyChainTradeLineItem'; | ||
} | ||
|
||
# Metadata accessor method | ||
sub metadata { | ||
|
@@ -143,6 +177,10 @@ sub parse_xml { | |
$self->{_metadata} = {}; | ||
$self->{_items} = (); | ||
|
||
my $ram = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'}; | ||
$ram .= ":" if $ram; | ||
my $udt = $self->{namespaces}->{'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'}; | ||
#foreach my $namespace (@{$self->{namespaces}}( | ||
# Retrieve scalar metadata from DOM | ||
foreach my $key ( keys %{$self->scalar_xpaths} ) { | ||
my $xpath = ${$self->scalar_xpaths}{$key}; | ||
|
@@ -152,6 +190,10 @@ sub parse_xml { | |
next; | ||
} | ||
my $value = $self->{dom}->findnodes($xpath); | ||
unless ($udt) { | ||
$value = $self->{dom}->findnodes('//' . $ram . 'DueDateDateTime','DateTimeString') if $key eq 'duedate'; | ||
$value = $self->{dom}->findnodes('//' . $ram . 'IssueDateTime','DateTimeString') if $key eq 'transdate'; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Diesen Block hier verstehe ich nicht. Das ist in der Schleife für alle scalaren xpaths, und macht dann eine Ausnahme für duedate und transdate wenn der udt namespace nicht gefunden wurde und sucht dann durch das ganze DOM nach den nodes? Gibt es da einen Präzedenzfall? Ist das ein bekannter Bug in einer Datei gewesen? Bitte zumindest dokumentieren was das sein soll. |
||
if ( $value ) { | ||
# Get rid of extraneous white space | ||
$value = $value->string_value; | ||
|
@@ -163,15 +205,14 @@ sub parse_xml { | |
} | ||
} | ||
|
||
|
||
# Convert payment code metadata field to Boolean | ||
# See https://service.unece.org/trade/untdid/d16b/tred/tred4461.htm for other valid codes. | ||
${$self->{_metadata}}{'direct_debit'} = ${$self->{_metadata}}{'direct_debit'} == 59 ? 1 : 0; | ||
|
||
my @items; | ||
$self->{_items} = \@items; | ||
|
||
foreach my $item ( $self->{dom}->findnodes(ITEMS_XPATH) ) { | ||
foreach my $item ( $self->{dom}->findnodes($self->items_xpath) ) { | ||
my %line_item; | ||
foreach my $key ( keys %{$self->item_xpaths} ) { | ||
my $xpath = ${$self->item_xpaths}{$key}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Das hier finde ich unschön.
Das ist ein bisschen akademisch, aber die Struktur hier ist ein Factory Pattern, wo die SL::XMLInvoice für eine Datei den passenden Worker instanziert. Das Instanzieren passiert hier aber nicht über einen Constructor, sondern in dem das hashref
$self
einfach in das entsprechende package ge-bless
-ed wird.Nach dem
bless
gilt das Worker-Objekt als fertig, und ab da sollte auch nicht mehr seinen Innereien gewühlt werden, sondern stattdessen mit den Objektmethoden drauf zugegriffen werden.Möglichkeiten das anders zu machen wären also:
sub namespaces
so, dass sie nicht mehr statisch ist (was sie eh nicht ist, weil sie ja zum Aufrufzeitpunkt schon ein Objekt hat), und lässt sie die namespaces selber in$self->{namespaces}
speichern. Dann ist in derSL::XMLInvoice
der Aufruf nur noch$self->namespaces($self->{dom})
oder sogar nur$self->namespaces
- weil es nicht mehr statisch ist.In beiden Fällen aber als Idee:
$self->{...}
) nur vorbless $self, $type
$self->method()
)