-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Moves actual sorting logic to separate class.
- Adds some unit tests for the DomDocumentSorter and XmlSorter classes.
- Loading branch information
Showing
5 changed files
with
496 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<?php | ||
|
||
class DomDocumentSorter | ||
{ | ||
/** | ||
* @param DOMDocument $p_oDocument | ||
* | ||
* @return DOMDocument | ||
*/ | ||
static public function sort(DOMDocument $p_oDocument) | ||
{ | ||
$oDocument = clone $p_oDocument; | ||
|
||
$oSorter = new self(); | ||
$oSorter->sortDomDocument($oDocument); | ||
|
||
return $oDocument; | ||
} | ||
|
||
/** | ||
* @param \DOMDocument $p_oDomDocument | ||
*/ | ||
public function sortDomDocument(DOMDocument $p_oDomDocument) | ||
{ | ||
foreach ($p_oDomDocument->childNodes as $t_oDomElement) { | ||
$this->sortDomElement($t_oDomElement, $p_oDomDocument); | ||
} | ||
} | ||
|
||
/** | ||
* Replace childNodes by sorted childNodes | ||
* | ||
* @param DOMElement $p_oDomElement | ||
* @param DOMDocument $p_oDocument | ||
*/ | ||
protected function sortDomElement(DOMElement $p_oDomElement) | ||
{ | ||
$this->sortAttributes($p_oDomElement); | ||
|
||
if ($p_oDomElement->hasChildNodes()) { | ||
$oChildNodes = $p_oDomElement->childNodes; | ||
$aChildren = array(); | ||
foreach ($oChildNodes as $t_sIndex => $t_oDomElement) { | ||
if ($t_oDomElement instanceof DOMText) { | ||
// Remove empty whitespace | ||
$sText = trim($t_oDomElement->textContent); | ||
if(empty($sText)){ | ||
$p_oDomElement->removeChild($t_oDomElement); | ||
} | ||
} else if($t_oDomElement instanceof DOMElement) { | ||
$aChildren[] = clone $t_oDomElement; | ||
$p_oDomElement->removeChild($t_oDomElement); | ||
} else { | ||
var_dump(get_class($t_oDomElement)); | ||
} | ||
unset($t_oDomElement); | ||
} | ||
|
||
// @FIXME: Things seem to go wrong round about here. | ||
// Either the sorting is wrong or text-nodes muddle things up or the | ||
// original nodes do not get properly removed and messes up things | ||
// when replacement get appended. | ||
$bSorted = usort($aChildren, function (DOMElement $p_oLeft, DOMElement $p_oRight) { | ||
return strcasecmp($p_oRight->tagName, $p_oLeft->tagName); | ||
}); | ||
|
||
/* | ||
* We can just add the first child right away | ||
* Every child after that we compare to that node | ||
* | ||
* If the child's tag name is alphabetically lower we move down | ||
* the chain (if there are any next sibling) until we find a sibling | ||
* who's name is lower than the current one | ||
* | ||
* The same logic applies up the chang for a higher sorting name | ||
*/ | ||
|
||
foreach ($aChildren as $t_oDomElement) { | ||
$this->sortDomElement($t_oDomElement); | ||
$p_oDomElement->appendChild(clone $t_oDomElement); | ||
} | ||
|
||
} | ||
} | ||
|
||
/** | ||
* replace attributes with sorted attributes | ||
* @param DOMElement $p_oDomNode | ||
*/ | ||
protected function sortAttributes(DOMElement $p_oDomNode) | ||
{ | ||
$oDOMNamedNodeMap = $p_oDomNode->attributes; | ||
if( $oDOMNamedNodeMap instanceof DOMNamedNodeMap){ | ||
/* Remove all attributes and place them back in order */ | ||
$aAttributes = array(); | ||
foreach ($oDOMNamedNodeMap as $t_sNodeName => $t_oAttribute) { | ||
/** @var DOMAttr $t_oAttribute */ | ||
$aAttributes[$t_oAttribute->name] = $t_oAttribute->value; | ||
$p_oDomNode->removeAttribute($t_sNodeName); | ||
} | ||
|
||
ksort($aAttributes); | ||
foreach ($aAttributes as $t_sAttributeName => $t_sNodeValue) { | ||
$p_oDomNode->setAttribute($t_sAttributeName, $t_sNodeValue); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit | ||
backupGlobals="false" | ||
backupStaticAttributes="false" | ||
bootstrap="vendor/autoload.php" | ||
cacheTokens="true" | ||
colors="true" | ||
convertErrorsToExceptions="true" | ||
convertNoticesToExceptions="true" | ||
convertWarningsToExceptions="true" | ||
forceCoversAnnotation="true" | ||
mapTestClassNameToCoveredClassName="true" | ||
printerClass="PHPUnit_TextUI_ResultPrinter" | ||
processIsolation="false" | ||
stopOnError="false" | ||
stopOnFailure="false" | ||
stopOnIncomplete="false" | ||
stopOnSkipped="false" | ||
strict="true" | ||
testSuiteLoaderClass="PHPUnit_Runner_StandardTestSuiteLoader" | ||
verbose="true" | ||
> | ||
<testsuites> | ||
<testsuite name="XmlDiff Test Suite"> | ||
<directory suffix=".php">./tests/</directory> | ||
</testsuite> | ||
</testsuites> | ||
</phpunit> |
Oops, something went wrong.