in reply to Problems with multiple records in xml file , Xpath

First we find all BaseItemDetails, then extract Description from each.

use strict; use warnings; use XML::XPath; use XML::XPath::XMLParser; my $xp = XML::XPath->new(filename => 'invoice.xml'); my $nodeset = $xp->find('//Invoice/InvoiceDetails/BaseItemDetails'); foreach my $node ($nodeset->get_nodelist) { my $description = $node->find('Description')->string_value; print " DES: $description\n"; }

Update: There is a nice tutorial here Using Perl XPath for converting Infopath XML files to Word Documents, also the source of my inspiration ;)

Replies are listed 'Best First'.
Re^2: Problems with multiple records in xml file , Xpath
by joppei (Initiate) on Mar 02, 2010 at 19:20 UTC
    Thx for the replies. I tried with your code and yes it gets all BaseItemid but now it gets printed 16 times , 1 for each Invoice record. Is there anyway to make the code only print the coresponding BaseItemids. And not run trough the whole file each time. Or do i have to edit somwhat in the xml to achive this. Ill try explain.. I want to print all the info from the xml, not just the BaseItemIds, so that it gets this output.

    Invoice1 (with all childs,all saved to string)

    Invoice2

    Invoice3

    This is how it works Now (wich is a mess, As i cant tell wich BaseItemId(s) Belong to wich Invoice record.

    Invoice1

    BaseItemIds (x 16)

    Invoice2

    BaseItemIds (x 16)

    ------------

    -------------

    Been looking at a endless amount of torturials & stuff, really banging my head here :/

      If you want to print all the info from the XML, than a better approach is to use the 'simplify' method of XML::Twig (or XML::Simple) to create a Perl data structure.

      use strict; use warnings; use XML::Twig; use Data::Dumper; my $twig = new XML::Twig(); my $config = $twig->parsefile('invoice2.xml')->simplify(); print Dumper( $config);

      With XML::XPath I see only a more tedious way (it's true that I don't have much experience with it.)

      Also I changed the xml a little:

      <Invoices> <Invoice> <InvoiceHeader> <InvoiceType>IT1</InvoiceType> <Supplier> <Name>Sup1</Name> <OrgNumber>Org1</OrgNumber> </Supplier> </InvoiceHeader> <InvoiceDetails> <BaseItemDetails> <Description>description11</Description> <PerQuantity></PerQuantity> </BaseItemDetails> <BaseItemDetails> <Description>description12</Description> <PerQuantity>101</PerQuantity> </BaseItemDetails> </InvoiceDetails> </Invoice> <Invoice> <InvoiceHeader> <InvoiceType>IT2</InvoiceType> <Supplier> <Name>Sup1</Name> <OrgNumber>Org2</OrgNumber> </Supplier> </InvoiceHeader> <InvoiceDetails> <BaseItemDetails> <Description>description21</Description> <PerQuantity></PerQuantity> </BaseItemDetails> <BaseItemDetails> <Description>description21</Description> <PerQuantity>101</PerQuantity> </BaseItemDetails> </InvoiceDetails> </Invoice> </Invoices>
      use strict; use warnings; use XML::XPath; use XML::XPath::XMLParser; my $xp = XML::XPath->new(filename => 'invoice2.xml'); my $nodeset = $xp->find('//Invoices/Invoice'); foreach my $node ($nodeset->get_nodelist) { my $it = $node->find('InvoiceHeader/InvoiceType')->string_value; print "IT: $it\n"; my $spn = $node->find('Supplier/Name')->string_value; print " SPN: $it\n"; my $des = $node->find('InvoiceDetails/BaseItemDetails/Description' +)->string_value; print " DES: $des\n"; # ... # You got the idea, yes? }

      Good coding, Stefan

      Update: 'TwigRoots' option is not needed in the XML::Twig example. You may want to use 'forcearray', 'keyattr' or other options to get a consistent data structure.

      Update2: Removed 'TwigRoots' option from the code.

      Within the loop for invoices, find('InvoiceDetails/BaseItemDetails') and loop though that list printing the descriptions.

      Other option would, to do some advertising, be to use XML::Rules. There's quite a few examples on Perlmonks.

      Jenda
      Enoch was right!
      Enjoy the last years of Rome.

        Thx for all the help. I finally got this working as i wanted yesterday. After reading around some on the xml:twig side i used xml:twig combined with the code i already had. Had a very simular xml:xpath build that`s was suggested here. Next time i would propably just stick to xml:twig as it seemed to work better. Now for making a web interface for some simple searching :)