blob: 0f8666225bf8559c4dae55e1301372ed5828b0cc [file] [log] [blame]
<?php
/**
* File containing the ezcDocumentXhtmlTableElementFilter class
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package Document
* @version //autogen//
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @access private
*/
/**
* Filter for XHtml table elements.
*
* Tables, where the rows are nor structured into a tbody and thead are
* restructured into those by this filter.
*
* @package Document
* @version //autogen//
* @access private
*/
class ezcDocumentXhtmlTableElementFilter extends ezcDocumentXhtmlElementBaseFilter
{
/**
* Filter a single element
*
* @param DOMElement $element
* @return void
*/
public function filterElement( DOMElement $element )
{
$type = false;
$aggregated = array();
$processed = array();
for ( $i = ( $element->childNodes->length - 1 ); $i >= -1; --$i )
{
// Get type of current row, or set row type to null, if it is no
// table row.
$child = $element->childNodes->item( $i );
$childNr = $i;
if ( $child &&
( $child->nodeType === XML_ELEMENT_NODE ) &&
( $child->tagName === 'tr' ) )
{
$rowType = $this->getType( $child );
}
else
{
$rowType = null;
}
// There are three different actions, which need to be performed in
// this loop:
// - Skip irrelevant nodes (whitespaces)
// - Aggregate tr nodes
// - Move tr nodes to new tbody / thead nodes, depending on their
// type, when the row type changes, we reached the last row, or
// their is some tbody / thead node found.
if ( ( count( $aggregated ) ) &&
( ( $i < 0 ) ||
( ( $rowType !== null ) &&
( $rowType !== $type ) ) ) )
{
// Move nodes to new subnode
$lastNode = end( $aggregated );
$parent = $lastNode->parentNode;
$newNode = new ezcDocumentPropertyContainerDomElement( $type );
$parent->insertBefore( $newNode, $lastNode );
$newNode->setProperty( 'type', $type );
// Append all aggregated nodes
$aggregated = array_reverse( $aggregated );
foreach ( $aggregated as $node )
{
$cloned = $node->cloneNode( true );
$newNode->appendChild( $cloned );
$parent->removeChild( $node );
}
// Clean up
$aggregated = array();
$type = false;
// Maybe we need to handle the current element again.
++$i;
}
if ( $child &&
( $child->nodeType !== XML_ELEMENT_NODE ) )
{
$child->parentNode->removeChild( $child );
continue;
}
elseif ( ( $rowType !== null ) &&
( !isset( $processed[$childNr] ) ) )
{
// Aggregate nodes
$aggregated[] = $child;
$processed[$childNr] = true;
$type = $rowType;
}
}
}
/**
* Estimate type of a row
*
* Estimate, if a row in a table is a header or a footer row. This
* estiamtion checks if there are more th elements, the td elements and
* returns either 'thead' or 'tbody' as the row type on base of that.
*
* @param DOMElement $element
* @return string
*/
protected function getType( DOMElement $element )
{
$thCount = $element->getElementsByTagName( 'th' )->length;
$tdCount = $element->getElementsByTagName( 'td' )->length;
return ( $thCount < $tdCount ) ? 'tbody' : 'thead';
}
/**
* Check if filter handles the current element
*
* Returns a boolean value, indicating weather this filter can handle
* the current element.
*
* @param DOMElement $element
* @return void
*/
public function handles( DOMElement $element )
{
return ( $element->tagName === 'table' );
}
}
?>