Skapa en XML som representerar filsystemet

Skapa en XML som representerar filsystemet

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>
Tags:
, , ,