20 Jul Skapa en XML som representerar filsystemet
Posted at 17:30h
in Uncategorized
I ett av våra projekt behövde vi skapa en XML utifrån filstruktur på en server.
Strukturen skulle visas med mappar först, i bokstavsordning, och sedan filer i bokstavsordning.
Skapandet av XML-filen var enkelt, men frågan var hur vi skulle sortera innehållet.
Det var dessutom önskvärt att kunna ändra sorteringsordningen i framtiden.
Lösningen var att stega igenom filsystemet och skapa en XML som sedan transformerades med en enkel XSL-mall. Genom att ändra XSL-mallen kan sorteringen ändras i efterhand utan att PHP-koden påverkas.
<?php
header("Content-type: text/xml; charset=iso-8859-1");
$start_dir = '/YOUR SERVERS BASE PATH FOR STORING FILES/PATH/PATH';
$domtree = new DOMDocument('1.0', 'ISO-8859-1');
/* create the root element of the xml tree */
$xmlRoot = $domtree->createElement("rows");
$domAttribute = $domtree->createAttribute('parent');
//Create attribute
$domAttribute->value = '0';
// Value for the created attribute
$xmlRoot->appendChild($domAttribute);
$xmlRoot = $domtree->appendChild($xmlRoot);
//Append it to root element
$folderElement; $folderName;
$fileElement; $fileName;
$parent;
$rit = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$start_dir,
FilesystemIterator::KEY_AS_PATHNAME |
FilesystemIterator::CURRENT_AS_FILEINFO |
FilesystemIterator::SKIP_DOTS
),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($rit as $path => $fileinfo) {
$level = $rit->getDepth();
$parent = ($level==0) ? $xmlRoot : $folderElement;
$exclude = "/MATCHING SUBSTRING FOR PATHS AND OR FILES TO EXCLUDE/";
$include = (strpos($path , $exclude)) === false ? true : false;
if($include){
$counter++;
$name = str_replace($start_dir, "", $path);
$folderTitle = ($level==0) ? $name : substr($name, strrpos($name, '/') + 1);
if ($fileinfo->isDir()) {
$folderName = $name ."/";
$folderElement = $domtree->createElement("row");
$domAttribute = $domtree->createAttribute('id');
$domAttribute->value = $id;
$folderElement->appendChild($domAttribute);
$domAttribute = $domtree->createAttribute('isFolder');
$domAttribute->value = "1";
$folderElement->appendChild($domAttribute);
$domAttribute = $domtree->createAttribute('fileName');
$domAttribute->value = $folderTitle;
$folderElement->appendChild($domAttribute);
$folderElement->appendChild($domAttribute);
$domAttribute = $domtree->createAttribute('filePath');
$domAttribute->value = $name;
$folderElement->appendChild($domAttribute);
$cell = $domtree->createElement("cell", $folderTitle);
$domAttribute = $domtree->createAttribute('image');
$domAttribute->value = "folder.gif";
$cell->appendChild($domAttribute);
$folderElement->appendChild($cell);
$folderElement->appendChild($domtree->createElement("cell",""));
//XPath - find parent
$xpath = new DomXpath($domtree);
$parts = explode('/', $name);
$lastPart = array_pop($parts);
$parentFolderName = (count($parts)>=1) ? implode('/', $parts) : '';
$rowNode = $xpath->query('//row[@filePath="'. $parentFolderName .'"][1]')->item(0);
$parent = ($rowNode instanceof DomElement) ? $rowNode : $xmlRoot;
$folderElement = $parent->appendChild($folderElement);
} else {
$fileName = $folderTitle;
$fileElement = $domtree->createElement("row");
$domAttribute = $domtree->createAttribute('id');
$domAttribute->value = $id;
$fileElement->appendChild($domAttribute);
$domAttribute = $domtree->createAttribute('isFolder');
$domAttribute->value = "2";
$fileElement->appendChild($domAttribute);
$domAttribute = $domtree->createAttribute('filePath');
$domAttribute->value = $fileName;
$fileElement->appendChild($domAttribute);
$cell = $domtree->createElement("cell", $fileName);
$domAttribute = $domtree->createAttribute('image');
$domAttribute->value = "file.gif";
$fileElement->appendChild($cell);
$fileElement->appendChild($domtree->createElement("cell","<input type='checkbox' class='selectFile' name='". $fileName ."-". $id ."'>"));
//XPath - find parent
$xpath = new DomXpath($domtree);
$parts = explode('/', $name);
$lastPart = array_pop($parts);
$parentFolderName = (count($parts)>=1) ? implode('/', $parts) : '';
$rowNode = $xpath->query('//row[@filePath="'. $parentFolderName .'"][1]')->item(0);
$parent = ($rowNode instanceof DomElement) ? $rowNode : $xmlRoot;
$fileElement = $parent->appendChild($fileElement);
}
}
}
$xml = $domtree->saveXML();
$xsl = new DOMDocument;
$xsl->load('fileRun-sort.xsl');
$proc = new XSLTProcessor();
$proc->importStyleSheet($xsl);
$sortedXml = $proc->transformToXML($domtree);
echo $sortedXml;
?>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="1.0">
<xsl:output encoding="ISO-8859-1" method="xml"/>
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<!-- Sort elements rows / row First sort by attribute isFolder then sort on attribute fileName (path) -->
<xsl:template match="rows | row">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*">
<xsl:sort select="@isFolder" data-type="text" order="ascending"/>
<xsl:sort select="@fileName" data-type="text" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!-- Remove attributes used for sorting -->
<xsl:template match="row/@isFolder" />
<xsl:template match="row/@filePath" />
</xsl:stylesheet>