spacer

Webref WebRef   Sitemap · Experts · Tools · Services · Newsletters · About i.com

home / programming / php / php4xml / chap10 / 2 To page 1To page 2current pageTo page 4
[previous] [next]

Professional PHP4 XML, Chapter 10: Putting It Together

Technical Lead
Thomson Reuters (Markets) LLC
US-NY-New York

Justtechjobs.com Post A Job | Post A Resume
Developer News
Microsoft Shows Off Silverlight 4, IE9 Plans
Metasploit Expands Vulnerability Test Framework
HyperCard Reborn?


Using SAX To Modify a Document

If we could use SAX to transform a document we can surely use it to modify it. In fact, the approach used to modify a document with SAX should be the same as used when transforming the document - write filters that perform some basic transformations, and then chain the filters if needed, to perform a more complex modification. When modifying a document, chaining will be less frequent but the filter approach is good because each transformation is a separate class that can be maintained and updated easily.

Using SAX filters we can write the following filter to add a product to our XML cart example:

class FilterAddProduct extends AbstractFilter 
{
    var $products = Array();

    function AddProduct($id, $name, $desc, $quantity, $unit_price) 
    {
        $elem = Array();
        $elem["pid"] = $id;
        $elem["name"] = $name;
        $elem["desc"] = $desc;
        $elem["quantity"] = $quantity;
        $elem["unit_price"] = $unit_price;
        $this->products[] = $elem;
    }

    function StartElementHandler($name, $attribs) 
    {
        $this->listener->StartElementHandler($name, $attribs);
        if ($name == "products") {
            // Perform insertions
            foreach ($this->products as $product) {
                $this->listener->StartElementHandler("product", 
                                          Array("pid" => $product["pid"]));
                // Name
                $this->listener->StartElementHandler("name", Array());
                $this->listener->CharacterDataHandler($product["name"]);
                $this->listener->EndElementHandler("name");

                // Desc
                $this->listener->StartElementHandler("desc", Array());
                $this->listener->CharacterDataHandler($product["desc"]);
                $this->listener->EndElementHandler("desc");

                // Quantity
                $this->listener->StartElementHandler("quantity", Array());
                $this->listener->CharacterDataHandler($product["quantity"]);
                $this->listener->EndElementHandler("quantity");

                // Unit_price
                $this->listener->StartElementHandler("unit_price", Array());
                $this->
                     listener->characterDataHandler($product["unit_price"]);
                $this->listener->EndElementHandler("unit_price");

                $this->listener->EndElementHandler("product");
            }
        }
    }

    function EndElementHandler($name) 
    {
        $this->listener->EndElementHandler($name);
    }

    function CharacterDataHandler($data) 
    {
        $this->listener->CharacterDataHandler($data);
    }
}

This filter lets us prepare the filter to add many products when parsing the document; we store the products to be added in a member array of the filter. When parsing the document, if the filter sees that a <products> element has started, it traverses the list of products to be added, generating the events needed to insert the elements on the XML file.

We can use the filter this way:

$f1 = new ExpatParser("cart.xml");
$f1->ParserSetOption(XML_OPTION_CASE_FOLDING, 0);

$f2 = new FilterAddProduct();
$f2->AddProduct("15", "foo", "foo bar", "1", "6");
$f2->AddProduct("17", "Goo", "GOO", "2", "16");

$f3 = new FilterOutput();
$f2->SetListener($f3);
$f1->SetListener($f2);

$f1->Parse();

To remove elements from an XML document using SAX, we can use the following filter:

class FilterRemoveProduct extends AbstractFilter 
{
    var $products = Array();
    var $ignore = 0;

    function RemoveProduct($id) 
    {
        $this->products[] = $id;
    }

    function StartElementHandler($name, $attribs) 
    {
        if ($name == "product") {
           if (in_array($attribs["pid"], $this->products)) {
               $this->ignore = 1;
           } else {
               $this->listener->StartElementHandler($name, $attribs);
           }
       } 
       if (!$this->ignore) {
           $this->listener->StartElementHandler($name, $attribs);
       }
    }

    function EndElementHandler($name) 
    {
        if (!$this->ignore) {
            $this->listener->EndElementHandler($name);
        } else {
            if ($name == "product") {
                $this->ignore = 0;
            }
        }
    }

    function CharacterDataHandler($data) 
    {
        if (!$this->ignore) {
            $this->listener->CharacterDataHandler($data);
        }
    }
} 

This filter can also store IDs of products to be deleted; we can use the removeProduct() method as many times as we want before parsing the document, preparing our chain to remove as many elements as we want.

We use a flag in the filter, and we turn the flag on each time a <product> element with an ID to be deleted starts. While the flag is on, we don't propagate events to the following filter, thus eliminating the element's text and subelements. When a <product> element ends, we turn the flag off (if it was on), to let further products pass to the filter. Ignoring SAX event propagation is a common way to eliminate elements from an XML document using SAX.

In the following example we add some products to the cart and then remove some others:

$f1 = new ExpatParser("cart.xml");
$f1->ParserSetOption(XML_OPTION_CASE_FOLDING, 0);
$f2 = new FilterAddProduct();
$f2->AddProduct("15", "foo", "foo bar", "1", "6");
$f2->AddProduct("17", "Goo", "GOO", "2", "16");

$f3 = new FilterRemoveProduct();
$f3->RemoveProduct("13");
$f3->RemoveProduct("15");

$f4 = new FilterOutput();
  
$f3->SetListener($f4);
$f2->SetListener($f3);
$f1->SetListener($f2);

$f1->Parse();

SAX scales very well for huge documents. Its resource consumption is constant for documents of any size, and it is fast. However, every modification needs coding, and at times it is complex. The same modifications are easy using DOM.


home / programming / php / php4xml / chap10 / 2 To page 1To page 2current pageTo page 4
[previous] [next]

internet.commediabistro.comJusttechjobs.comGraphics.com

Search:

WebMediaBrands Corporate Info

Legal Notices, Licensing, Permissions, Privacy Policy.
Advertise | Newsletters | Shopping | E-mail Offers | Freelance Jobs

webref The latest from WebReference.com Browse >
Rolling Out Your Own HTML Application Version Control · HTML 5: Client-side Storage · Working with Ajax Server Extensions
Sitemap · Experts · Tools · Services · Email a Colleague · Contact FREE Newsletters 
 The latest from internet.com
Wi-Fi Product Watch, November 2009 · Chip Market Recovering From '08 Collapse · Low-Cost Tools to Kickstart Your New Business

Created: August 19, 2002
Revised: August 19, 2002

URL: http://webreference.com/programming/php/php4xml/chap10/2/3.html