DOM-Based XML Parser Modules


The XML::DOM Perl module is a Perl implementation of the W3C DOM Level 1 specification that was written by T. J. Mather. XML::DOM is an extension of the XML::Parser Perl module that parses XML data (either files or strings). It generates a hierarchical data structure containing the contents of the XML document.The API provided by the XML::DOM Perl module to access the hierarchical data is directly based on the requirements in the W3C specification. In addition, the XML::DOM Perl module has also added several additional methods that aren't required by the standard. Most of these additions have been added as helper methods that make the module a little easier to use.

This module is one of the more widely used XML parsing modules. As a result of its widespread use, this module is very stable, very well documented, and is considered by many to be the de facto XML parsing module for Perl.

Note

For additional information on the W3C DOM Level 1 specification, please see http://www.w3.org/TR/REC-DOM-Level-1/.


XML::DOM Perl Module Example

Now that you've had an introduction to the XML::DOM Perl module, let's take a look at an example to see how we might be able to use it as the basis for an application.

Let's assume that your company is one of several organizations involved with monitoring network traffic on an experimental network. During a test period, a network sniffer records all the Internet Protocol (IP) packets transmitted during the course of the testing period.The network sniffer parses the IP packets, extracts the pertinent information, and stores the contents of the IP packets in the form of an XML document. XML was selected as the format for the message traffic to facilitate data exchange among the different organizations involved with the testing. Our task is to use the XML::DOM module to generate a report from the recorded data in a particular format.

During the testing, we don't need to store all the fields in each IP packet, just those that are important for data analysis. Listing 4.11 shows the DTD that was developed to support these requirements. As you can see, this is a simple DTD that is basically made up of multiple <packet> elements. Note that each <packet> element has a unique sequence identification number that is an attribute with an ID type. The ID attribute type requires that each seqnum attribute is unique throughout the XML document.

Listing 4.11 DTD that defines the format of the network sniffer log. (Filename:ch4_dom_netlog.dtd)
 <?xml version="1.0" encoding="UTF-8"?>  <!ELEMENT sniffer_data (packet*)>  <!ELEMENT packet (protocol, timestamp, source, dest)>  <!ATTLIST packet seqnum ID #REQUIRED>  <!ELEMENT protocol (#PCDATA)>  <!ELEMENT timestamp (#PCDATA)>  <!ELEMENT source (#PCDATA)>  <!ELEMENT dest (#PCDATA)> 

The XML schema that describes the same XML document is shown in Listing 4.12.

Listing 4.12 XML schema that defines the format of the network sniffer log. (Filename: ch4_dom_netlog.xsd)
 <?xml version="1.0" encoding="UTF-8"?>  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"  elementFormDefault="qualified">     <xs:element name="dest" type="xs:string"/>     <xs:element name="packet">       <xs:complexType>           <xs:sequence>              <xs:element ref="protocol"/>              <xs:element ref="timestamp"/>              <xs:element ref="source"/>              <xs:element ref="dest"/>           </xs:sequence>           <xs:attribute name="seqnum" type="xs:ID" use="required"/>        </xs:complexType>     </xs:element>     <xs:element name="protocol" type="xs:string"/>     <xs:element name="sniffer_data">        <xs:complexType>           <xs:sequence>              <xs:element ref="packet" minOccurs="0" maxOccurs="unbounded"/>           </xs:sequence>        </xs:complexType>     </xs:element>     <xs:element name="source" type="xs:string"/>     <xs:element name="timestamp" type="xs:positiveInteger"/>  </xs:schema> 

A sample XML document that contains the recorded network traffic is shown in Listing 4.13. As you can see, each <packet> element has a unique sequence number and several required elements ( <protocol> , <timestamp> , <source> , and destination hostname ( <dest> )). In a real-world application, the timestamp could be the standard Unix epoch timestamp (seconds since January 1, 1970), the number of seconds since midnight, or relative to the beginning of the test period.

Listing 4.13 Network traffic sniffer log in XML. (Filename: ch4_dom_netlog.xml)
 <?xml version="1.0" encoding="UTF-8"?>  <!DOCTYPE sniffer_data SYSTEM "netlog2.dtd">  <sniffer_data>     <packet seqnum="tx_1">        <protocol>SMTP</protocol>        <timestamp>1</timestamp>       <source>scooby</source>        <dest>smtp_server</dest>     </packet>     <packet seqnum="tx_2">        <protocol>FTP</protocol>        <timestamp>4</timestamp>        <source>shaggy</source>        <dest>ftp_server</dest>     </packet>     <packet seqnum="tx_3">        <protocol>SNMP</protocol>        <timestamp>7</timestamp>        <source>sys_admin</source>        <dest>gateway</dest>     </packet>     <packet seqnum="tx_4">        <protocol>DNS</protocol>        <timestamp>8</timestamp>        <source>casper</source>        <dest>dns_server</dest>     </packet>     <packet seqnum="tx_5">        <protocol>HTTP</protocol>        <timestamp>9</timestamp>        <source>casper</source>        <dest>web_server</dest>     </packet>     <packet seqnum="tx_6">        <protocol>SSH</protocol>        <timestamp>11</timestamp>        <source>speedracer</source>        <dest>accounting</dest>     </packet>     <packet seqnum="tx_7">        <protocol>SMTP</protocol>        <timestamp>13</timestamp>        <source>scooby</source>        <dest>smtp_server</dest>     </packet>     <packet seqnum="tx_8">        <protocol>SMTP</protocol>        <timestamp>13</timestamp>        <source>scooby</source>        <dest>smtp_server</dest>     </packet>  </sniffer_data> 

Now that we've seen the data, we need to create a program that generates an output report summarizing the data.The report should have the following format:

 Sequence Number:  Protocol:  Timestamp:  Source Hostname:  Destination Hostname: 

A sample section of the report for the first <packet> element in the XML document would contain the following information:

 Sequence Number: tx_1  Protocol: SMTP  Timestamp: 1  Source Hostname: Scooby  Destination Hostname: smtp_server 

In addition, we want to keep a count of how many packets we see on the network for each protocol.The Perl program to parse and summarize the network traffic log is shown in Listing 4.14.

Listing 4.14 XML::DOM-based program to parse and summarize the network sniffer log. (Filename: ch4_dom_app.pl)
 1.   use strict;  2.   use XML::DOM;  3.  4.   # Declare a few variables.  5.   my ($packet, %protoCount, $nodeName, @pktInfoArray, $pktInfo);  6.  7.   # Instantiate a new XML::DOM parser.  8.   my $parser = XML::DOM::Parser->new(); 9.  10.  # Parse the input XML document.  11.  my $doc = $parser->parsefile ("ch4_dom_netlog.xml");  12.  my $root = $doc->getDocumentElement();  13.  14.  # Retrieve an array of all nodes.  15.  my @packetArray = $root->getChildNodes();  16.  17.  # Loop through the array.  18.  foreach $packet (@packetArray) {  19.    if ($packet->getNodeType() == ELEMENT_NODE) {  20.       print "Seqnum: " . $packet->getAttribute("seqnum") . "\n";  21.       @pktInfoArray = $packet->getChildNodes();  22.  23.       foreach $pktInfo (@pktInfoArray) {  24.  25.         if ($pktInfo->getNodeType() == ELEMENT_NODE) {  26.            $nodeName = $pktInfo->getNodeName();  27.            $nodeName =~ s/(\w+)/\u \L/g;  28.  29.            print "$nodeName";  30.  31.            if ($pktInfo->getNodeName() eq "protocol') {  32.               if ($protoCount{$pktInfo->getFirstChild()->getData}) {  33.                   $protoCount{$pktInfo->getFirstChild()->getData}++;  34.               }  35.               else {  36.                  $protoCount{$pktInfo->getFirstChild->getData} = 1;  37.               } 38.            }  39.            print " : " . $pktInfo->getFirstChild()->getData . "\n";  40.         }  41.      }  42.      print "\n";  43.   }  44.  }  45.  46.  my ($key);  47.  print "\n----------------------------\n";  48.  print "Protocol Summary\n";  49.  foreach $key (keys %protoCount) {  50.     print "$key\t$protoCount{$key}\n";  51.  } 

Standard Pragmas

1 “5 The opening section of our program contains our standard use pragma ( use strict ). Because we're using the XML::DOM module, we'll need to include the use XML::DOM pragma as well. A few of our global scalars, arrays, and hashes are also declared in this opening block.

 1.   use strict;  2.   use XML::DOM;  3.  4.   # Declare a few variables.  5.   my ($packet, %protoCount, $nodeName, @pktInfoArray, $pktInfo); 

Initialization and Parsing

7 “12 This section of the program performs the initialization for the parser module and actually parses the document.There are several important steps that take place in this portion of the program.

The first step in the Perl program is to create a new XML::DOM parser object, which is named $parser . We need a parser object, so we can call the parsefile method. Second, we call the parsefile method, which parses the XML document specified in the argument and then returns an XML:: DOM::Document object that we have named $doc . This XML::DOM:: Document object has a tree structure consisting of node objects.The getDocumentElement method provides us with direct access to the node that is the root element of the entire document. The getChildNodes() method returns an array of all nodes that are children of the current node. All elements in the document are children of the root element, so we now have access to all elements in the XML document.

 7.   # Instantiate a new XML::DOM parser.  8.   my $parser = XML::DOM::Parser->new();  9.  10.  # Parse the input XML document.  11.  my $doc = $parser->parsefile ("ch4_dom_netlog.xml");  12.  my $root = $doc->getDocumentElement(); 

Extracting the Parsed Information

14 “51 The array @packetArray contains all the <packet> elements in our XML document.We'll need to loop through the array using a foreach() loop to access the individual packet elements.

At the first if() statement on line 19, we need to check and verify that the current <packet> is an element. Note that the ELEMENT_NODE type is a constant by the XML::DOM Perl module. Based on the design of our XML document, each time through the outermost foreach() loop, we'll see another packet element.This can be easily verified by the getNodeType method. It returns the current node type (for example, element, attribute, cdata, and so forth).

 14.  # Retrieve an array of all nodes.  15.  my @packetArray = $root->getChildNodes();  16.  17.  # Loop through the array.  18.  foreach $packet (@packetArray) {  19.    if ($packet->getNodeType() == ELEMENT_NODE) {  20.       print "Seqnum: " . $packet->getAttribute("seqnum") . "\n";  21.       @pktInfoArray = $packet->getChildNodes();  22.  23.       foreach $pktInfo (@pktInfoArray) {  24.  25.         if ($pktInfo->getNodeType() == ELEMENT_NODE) {  26.            $nodeName = $pktInfo->getNodeName();  27.            $nodeName =~ s/(\w+)/\u \L/g;  28.  29.            print "$nodeName";  30.  31.            if ($pktInfo->getNodeName() eq "protocol") {  32.               if ($protoCount{$pktInfo->getFirstChild()->getData}) {  33.                  $protoCount{$pktInfo->getFirstChild()->getData}++;  34.               }  35.               else {  36.                  $protoCount{$pktInfo->getFirstChild->getData} = 1;  37.               }  38.            }  39.            print " : " . $pktInfo->getFirstChild()->getData . "\n";  40.         }  41.      }  42.      print "\n";  43.    }  44.  }  45.  46.  my ($key);  47.  print "\n----------------------------\n";  48.  print "Protocol Summary\n";  49.  foreach $key (keys %protoCount) {  50.     print "$key \t$protoCount{$key}\n";  51.  } 

Note

A full listing of the valid predefined constants can be found in the XML::DOM perldoc.


After we verify that we've received an element back from the array, we're at a packet node in the DOM tree. First, we retrieve the packet's only attribute (named seqnum ) by using the getAttribute() method.

Now that we've retrieved the seqnum attribute from the <packet> element node, we're ready to retrieve the child nodes of the packet element using the getChildNodes() method.The @pktInfoArray array contains all the nodes that are children of the <packet> element. So, the @pktInfoArray array contains <protocol> , <timestamp> , <source> , and <dest> elements. Looping through the array, we use the getNodeName() method to retrieve the name of the current node, and then the getFirstChild()->getData() method to retrieve the character data stored in the element.While looping through all the elements, we're also counting the number of occurrences of each protocol type and accumulating the results in a hash named %protoCount .

The output report generated by the XML::DOM-based Perl program is shown in Listing 4.15.

Listing 4.15 Output from the XML::DOM parsing program. (Filename: ch4_dom_report.txt)
 Seqnum: tx_1  Protocol : SMTP  Timestamp : 1  Source : scooby  Dest : smtp_server  Seqnum: tx_2  Protocol : FTP  Timestamp : 4  Source : shaggy  Dest : ftp_server  Seqnum: tx_3  Protocol : SNMP  Timestamp : 7  Source : sys_admin  Dest : gateway  Seqnum: tx_4  Protocol : DNS  Timestamp : 8  Source : casper  Dest : dns_server Seqnum: tx_5  Protocol : HTTP  Timestamp : 9  Source : casper  Dest : web_server  Seqnum: tx_6  Protocol : SSH  Timestamp : 11  Source : speedracer  Dest : accounting  Seqnum: tx_7  Protocol : SMTP Timestamp : 13  Source : scooby  Dest : smtp_server  Seqnum: tx_8  Protocol : SMTP  Timestamp : 13  Source : scooby  Dest : smtp_server  ---------------------------- Protocol Summary  SNMP 1  FTP 1  DNS 1  SMTP 3  SSH 1  HTTP 1 

Note

For additional information on the XML::DOM Perl (including all the possible options), please take a look at the available online documentation by using perldoc XML::DOM.


XML::LibXML

XML::LibXML is a Perl interface to the libxml2 C library developed for the Gnome project.The XML::LibXML Perl module was developed by Matt Sergeant and Christian Glahn while the libxml2 C library was developed by Daniel Velliard. XML::LibXML conforms to the DOM2 standard.

Unlike several of the tree-based parsers that we have discussed so far in this chapter (for example, XML::Simple, XML::Twig), the XML::LibXML Perl module isn't built on top of XML::Parser. If you remember our original discussion back in Chapter 3 about XML::Parser, you'll recall that it doesn't implement actual DOM, SAX, or XPath interfaces. XPath is discussed a little later in Chapter 8, "XML Transformation and Filtering."

Both XML::Parser and all the Perl modules built upon it are severely limited regarding support for standards. However, libxml2 was developed after the DOM, SAX, and XPath standards were mature, so fortunately for us, libxml2 supports the DOM, SAX, and XPath APIs. Depending on your task at hand, you'll have access to all three APIs in the same module. The advantage of having a DOM and SAX API in the same Perl module is that you can take advantage of a DOM tree and SAX events. For example, you can walk up and down an in-memory tree and generate SAX events.

XML::LibXML Example

Now that you have an understanding of the capabilities of the XML::LibXML module, let's take a look at an example. Assume that your company has purchased new accounting software to manage all the company billing records. Unfortunately, the new software isn't compatible with the old software (not an unrealistic example). Let's say that the old software can dump the current customer information into an XML document; however, the new accounting package can't accept XML data as input. Instead, it expects to see the data in a particular text-based format.Your task is to develop a parser to read the XML document and generate the required report.

Our first task is to review the input XML document format. Listing 4.16 shows the DTD for the XML document that contains our accounts receivable information.

Listing 4.16 DTD that describes the accounts receivable information. (Filename: ch4_libxml_customers.dtd)
 <?xml version="1.0" encoding="UTF-8"?>  <!ELEMENT customer_data (customer*)>  <!ELEMENT customer (name, balance, due_date)>  <!ATTLIST customer account_number ID #REQUIRED>  <!ELEMENT name (#PCDATA)>  <!ELEMENT balance (#PCDATA)>  <!ELEMENT due_date (#PCDATA)> 

As you can see, this is a fairly simple DTD that contains multiple occurrences of the <customer> element. Our example is based on a simple <customer> element that only contains the <name> , <balance> , and <date> child elements. In a real world application, we would expect a customer element to contain a few more child elements. For example, you could expect to see elements such as an account number, mailing address, telephone number, credit card number, and possibly even a transaction history. However, the same capabilities of the XML::LibXML module that will apply to this simple example can easily be extended to apply to a more complex example. An XML schema that describes our XML document is shown in Listing 4.17.

Listing 4.17 Accounts receivable schema. (Filename: ch4_libxml_customers.xsd)
 <?xml version="1.0" encoding="UTF-8"?>  <!W3C Schema generated by XML Spy v4.2 U (http://www.xmlspy.com)>  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"  elementFormDefault="qualified">     <xs:element name="balance" type="xs:float"/>     <xs:element name="customer">        <xs:complexType>          <xs:sequence>              <xs:element ref="name"/>              <xs:element ref="balance"/>              <xs:element ref="due_date"/>           </xs:sequence>           <xs:attribute name="account_number" type="xs:ID" use="required"/>        </xs:complexType>     </xs:element>     <xs:element name="customer_data">        <xs:complexType>           <xs:sequence>              <xs:element ref="customer" minOccurs="0" maxOccurs="unbounded"/>           </xs:sequence>        </xs:complexType>     </xs:element>     <xs:element name="due_date" type="xs:date"/>     <xs:element name="name" type="xs:string"/>  </xs:schema> 

Now that we understand the format of our input XML document, let's take a look at a sample XML document that is shown in Listing 4.18. Remember, XML data is not always in a standalone file. It can just as easily be stored in a Perl scalar variable, or sent to an application through a file handle (socket). Our sample data has information for six customers. Note that each <customer> element has a unique account_number attribute.

Listing 4.18 Accounts receivable data in XML. (Filename: ch4_libxml_customers.xml)
 <?xml version="1.0" encoding="UTF-8"?>  <!DOCTYPE customer_data SYSTEM "ch4_libxml_customers.dtd">  <customer_data>     <customer account_number="cid_1">        <name>Joseph Burns</name>        <balance>19.95</balance>        <due_date>May 5</due_date>     </customer>     <customer account_number="cid_2">        <name>Kayla Burns</name>       <balance>29.95</balance>        <due_date>May 12</due_date>     </customer>     <customer account_number="cid_3">        <name>Roger Smith</name>        <balance>100.25</balance>        <due_date>May 19</due_date>     </customer>     <customer account_number="cid_4">        <name>James Kennedy</name>        <balance>0.00</balance>        <due_date>N/A</due_date>     </customer>     <customer account_number="cid_5">        <name>Margaret Pelligrino</name>        <balance>0.00</balance>        <due_date>N/A</due_date>     </customer>     <customer account_number="cid_6">        <name>Joseph Jones</name>        <balance>1000.00</balance>        <due_date>May 22</due_date>     </customer>  </customer_data> 

Assume that the new accounting software requires input in the following format:

 Account Number:  Customer Name:  Balance:  Due Date: 

A sample of the report using only the first <customer> element in the XML document would contain the following information:

 Account Number: cid_1  Customer Name: Joseph Burns  Balance: 19.95  Due Date: May 5 

The XML::LibXML-based program used to generate the required output from the input XML document is shown in Listing 4.19. Let's work our way through the example and explain each of the sections.

Listing 4.19 XML::LibXML-based program used to parse the accounts receivable data. (Filename: ch4_libxml_app.pl)
 1.   use strict;  2.   use XML::LibXML;  3.  4.   my $file = "ch4_libxml_customers.xml";  5.  6.   # Instantiate a new XML::LibXML parser.  7.   my $parser = XML::LibXML->new();  8.  9.   # Parse the XML document.  10.  my $tree = $parser->parse_file($file);  11.  my $root = $tree->getDocumentElement;  12.  13.  # Retrieve an array of all customers.  14.  my @customers = $root->getElementsByTagName('customer');  15.  16.  my $total;  17.  18.  print "Accounts Receivable Report\n";  19.  print "--------------------------\n";  20.  21.  # Loop through the array of all customers.  22.  foreach my $customer (@customers) {  23.    my $account_num = $customer->getAttribute('account_number');  24.    print "Account Number: $account_num \n";  25.  26.    my @name = $customer->getElementsByTagName('name');  27.    my $thisName = $name [0]->getFirstChild->getData();  28.    print "Customer Name: $thisName \n";  29.  30.    my @balance = $customer->getElementsByTagName('balance');  31.    my $thisBalance = $balance [0]->getFirstChild->getData();  32.    print "Balance: $$thisBalance\n";  33.    $total += $thisBalance; 34.  35.    my @due_date = $customer->getElementsByTagName('due_date');  36.    my $thisDueDate = $due_date [0]->getFirstChild->getData();  37.    print "Due Date: $thisDueDate\n\n";  38.  }  39.  40.  print "---------------------------\n";  41.  print "Total Due: $$total\n"; 
Standard Pragmas

1 “2 Similar to all our examples, the opening section contains the recommended pragma ( use strict ). Because we're using the XML:: LibXML module, we need the pragma use XML::LibXML to load the XML::LibXML module.

 1.   use strict;  2.   use XML::LibXML; 
Parsing the XML Data with XML::LibXML

4 “11 The initial calls to XML::LibXML are similar to those of other parsers. The first step in parsing an XML document with XML::LibXML is to create a new XML::LibXML object by calling the constructor with the function new() .

The XML::LibXML supports three types of input for the XML data: as a Perl scalar, as a file handle (for example, a socket connection), and as a standalone file. Depending on the location of the XML data (that is, in a file, scalar, or filehandle), you'll need to call the appropriate method to parse the XML data. In our case, the XML data is contained in a file named customers.xml, so we use the parse_file() method.

After calling the parse_file() method, the document has been parsed, and an XML::LibXML::Document DOM object named $tree was returned. Now that we have a handle to the DOM object through the $tree scalar, we can call the method getElementsByTagName() . This method returns an array containing all occurrences of a particular element, and in our case, we want all the <customer> elements.

 4.   my $file = "ch4_libxml_customers.xml";  5.  6.   # Instantiate a new XML::LibXML parser.  7.   my $parser = XML::LibXML->new();  8.  9.   # Parse the XML document.  10.  my $tree = $parser->parse_file($file);  11.  my $root = $tree->getDocumentElement; 
Retrieving the Parsed Information

13 “41 Now that we have all the customer elements (stored in the @customer array), we can loop through all the elements and extract the child elements and attributes that we need to generate our report. The first thing that we do is extract the account_number attribute from each element by using the following method:

 my $account_num = $customer>getAttribute('account_number'); 

All the other required information (that is, the character data) contained in the other elements is extracted using the following method:

 my @name = $customer->getElementsByTagName('name'); 

This method returns an array of XML::LibXML::Node objects representing all occurrences of the <name> element for the current <customer> element. Because there is only one <name> element for each <customer> element, we're always going to be interested in the first element in the array (identified by index [0] ). Up until this point, we're manipulating objects that contain the character data.To extract the character data in the elements, we need to use the following method:

 my $thisName = $name [0]->getFirstChild->getData(); 

Note that we're accessing the first element of the @name array (because there is only one element in the array in our case).This method of creating the object array and accessing the character data is repeated for each child element of the <customer> element.

One other task that we're performing as part of the report generation is to keep a running total of the accounts receivable. This was easily accomplished with a variable that was declared outside the for() statement that loops through all the <customer> elements.We then increment the total for the individual total of each customer.

 13.  # Retrieve an array of all customers.  14.  my @customers = $root->getElementsByTagName('customer');  15.  16.  my $total;  17.  18.  print "Accounts Receivable Report\n";  19.  print "--------------------------\n";  20.  21.  #Loop through the array of all customers.  22.  foreach my $customer (@customers) {  23.    my $account_num = $customer->getAttribute('account_number');  24.    print "Account Number:$account_num\n";  25.  26.    my @name = $customer->getElementsByTagName('name');  27.    my $thisName = $name [0]->getFirstChild->getData();  28.    print "Customer Name:$thisName\n";  29.  30.    my @balance = $customer->getElementsByTagName('balance');  31.    my $thisBalance = $balance [0]->getFirstChild->getData();  32.    print "Balance: $$thisBalance\n";  33.    $total += $thisBalance;  34.  35.    my @due_date = $customer->getElementsByTagName('due_date');  36.    my $thisDueDate =$due_date [0]->getFirstChild->getData();  37.    print "Due Date:$thisDueDate\n\n";  38.  }  39.  40.  print "---------------------------\n";  41.  print "Total Due: $$total\n"; 

The accounts receivable report generated by the XML::LibXML Perl program is shown in Listing 4.20.

Note

If you ever need to track billing records and calculate billing cycles, there are a number of Perl modules that will make that job much easier. A potentially useful module is the Date::Calc Perl module. It performs all types of calculations based on the Gregorian calendar. For example, let's say you need to calculate dates based on 90-day billing cycles ”this module can calculate the next billing date.


Listing 4.20 Output accounts receivable report generated by the XML::LibXML-based Perl program. (Filename: ch4_libxml_report.txt)
 Accounts Receivable Report  -------------------------- Account Number: cid_1  Customer Name: Joseph Burns  Balance: .95  Due Date: May 5  Account Number: cid_2  Customer Name: Kayla Burns  Balance: .95  Due Date: May 12  Account Number: cid_3  Customer Name: Roger Smith  Balance: 0.25  Due Date: May 19  Account Number: cid_4  Customer Name: James Kennedy  Balance: 
 Accounts Receivable Report -------------------------- Account Number: cid_1 Customer Name: Joseph Burns Balance: $19.95 Due Date: May 5 Account Number: cid_2 Customer Name: Kayla Burns Balance: $29.95 Due Date: May 12 Account Number: cid_3 Customer Name: Roger Smith Balance: $100.25 Due Date: May 19 Account Number: cid_4 Customer Name: James Kennedy Balance: $0.00 Due Date: N/A Account Number: cid_5 Customer Name: Margaret Pelligrino Balance: $0.00 Due Date: N/A Account Number: cid_6 Customer Name: Joseph Jones Balance: $1000.00 Due Date: May 22 Total Due: $1150.15 
.00 Due Date: N/A Account Number: cid_5 Customer Name: Margaret Pelligrino Balance:
 Accounts Receivable Report -------------------------- Account Number: cid_1 Customer Name: Joseph Burns Balance: $19.95 Due Date: May 5 Account Number: cid_2 Customer Name: Kayla Burns Balance: $29.95 Due Date: May 12 Account Number: cid_3 Customer Name: Roger Smith Balance: $100.25 Due Date: May 19 Account Number: cid_4 Customer Name: James Kennedy Balance: $0.00 Due Date: N/A Account Number: cid_5 Customer Name: Margaret Pelligrino Balance: $0.00 Due Date: N/A Account Number: cid_6 Customer Name: Joseph Jones Balance: $1000.00 Due Date: May 22 Total Due: $1150.15 
.00 Due Date: N/A Account Number: cid_6 Customer Name: Joseph Jones Balance: 00.00 Due Date: May 22 Total Due: 50.15

Note

For additional XML::LibXML module information (including all the possible options), please take a look at the available online documentation by using perldoc XML::LibXML.




XML and Perl
XML and Perl
ISBN: 0735712891
EAN: 2147483647
Year: 2002
Pages: 145

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net