Collection and select

Sometimes you need to get a lot of information from the database and you need it fast. The way to get this information normally would be to use the Magento collection for the model. It would look like this:

$collection = Mage::getModel('customer/customer')->getCollection()
    ->addNameToSelect()
    ->joinAttribute('billing_city', 'customer/city', 'default_billing', null, 'left');

foreach ($collection as $customer) {
    // Use $customer
}

The problem with this way of getting the information is that it loads all customer information into memory, which can take a long time when you have many customers.

The solution to this performance problem is that you read the customers one at a time by using the select that was created.

$select = $collection->getSelect();
$stmt = $select->query();

while ($row = $stmt->fetch()) {
    // Use $row
}

This is often many times faster and won't fill your memory.

XML-lister

XML lister is a small program that lists the elements, values and attributes of XML files.

<?xml version="1.0"?>
<layout>
    <default>
        <reference name="root">
            <reference name="content">
                <block name="product.info">
                    <action method="test">
                        <param>test</param>
                        <param2>test2</param2>
                    </action>
                </block>
            </reference>
        </reference>
    </default>
</layout>

XML lister will print the following list:

layout  
layout/default  
layout/default/reference    
layout/default/reference@name   root
layout/default/reference/reference  
layout/default/reference/reference@name content
layout/default/reference/reference/block    
layout/default/reference/reference/block@name   product.info
layout/default/reference/reference/block/action 
layout/default/reference/reference/block/action@method  test
layout/default/reference/reference/block/action/param   test
layout/default/reference/reference/block/action 
layout/default/reference/reference/block/action/param2  test2
layout/default/reference/reference/block/action 
layout/default/reference/reference/block    
layout/default/reference/reference  
layout/default/reference    
layout/default  
layout  

A few days ago I wanted to find out if there are places in Magento layout XML files where reference elements are used inside other reference elements. With XML lister it becomes really easy to find places like this.

find app/design -name '*.xml' | xargs xml-lister --filename | grep reference/reference

With the list it becomes really easy to find the files where a certain construct is used.

Rewrite XML with xmlstarlet

XML Starlet is a program that makes transforming XML documents really simple.

The command that you need to transform an XML document is the following.

xmlstarlet tr [<options>] <xsl-file> {-p|-s <name>=<value>} [ <xml-file-or-uri> ... ]

The XSL file that transforms a document to itself is this. It copies all elements, attributes and texts. We can extend this file to remove, add, or transform elements.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

To remove an element, we match an element and don't call apply-elements inside it. This example will remove the remove me element.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <!-- Remove the element -->
    <xsl:template match="remove-me">
    </xsl:template>
</xsl:stylesheet>

To add an element, we just add the part we would like to add. If it needs to be in a certain place, we can add an extra xsl:template rule. The this-will-get-added element will be inserted after the element element.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="element">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>

        <this-will-get-added></this-will-get-added>
    </xsl:template>
</xsl:stylesheet>

To transform an element we remove xsl:copy and replace it with the elements we need. If we keep the xsl:apply-elements tag in the xsl:template tag, we copy everything inside the element in it's place.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="element">
        <my-new-element>
            <xsl:apply-templates select="@* | node()" />
        </my-new-element>
    </xsl:template>
</xsl:stylesheet>

XSL used in this way becomes quite simple to use. With these three patterns we can extend the identity transformation and get quite a bit of power when we transform XML documents.

Welcome

My name is Peter Stuifzand. You're reading my personal website.

Profiles

Peter Stuifzand
peter.stuifzand@gmail.com
Zwolle, The Netherlands