2

I have a function in PHP that retrieves all the directories and files from a given path. This returns me an array like:

array(
    "dirname1" => array(
        "dirname2" => array(
            "dirname3" => array(
                "0" => "file1",
                "1" => "file2",
                "2" => "file3"
            ),
            "0" => "file4",
            "1" => "file5",
            "2" => "file6",
            "dirname4" => array(
                "0" => "file7",
                "1" => "file8"
            )
        ),
        "0" => "file9",
        "1" => "file10"
    ),
    "0" => "file11",
    "1" => "file12",
    "2" => "file13"
);

What I finally need is a multidimensional (don't know if is the exactly word) list with <ul /> and <li /> generated with XSLT 1.0 from a XML file, like:

<ul>
    <li class="dirname">
        dirname1
        <ul>
            <li class="dirname">
                Dirname2
                <ul>
                    <li class="dirname">
                        Dirname3
                        <ul>
                            <li>file1</li>
                            <li>file2</li>
                            <li>file3</li>
                        </ul>
                    </li>
                    <li>file4</li>
                    <li>file5</li>
                    <li>file6</li>
                    <li class="dirname">
                        dirname4
                        <ul>
                            <li>file7</li>
                            <li>file8</li>
                        </ul>
                    </li>
                </ul>
            </li>
            <li>file9</li>
            <li>file10</li>
        </ul>
    </li>
    <li>file11</li>
    <li>file12</li>
    <li>file13</li>
</ul>

And finally, inside every <li /> I need the path in a <a />, like:

<li class="dirname"><a href="/dirname1">dirname1</a></li>

<li><a href="/dirname1/dirname2/dirname3/file1">file1</a></li>

<li><a href="/dirname1/file9">file9</a></li>

Actually I don't have the XML that I need to convert because I don't know what can be a nice structure for then convert it to XSLT 1.0. I have the paths inside the <a />. I can do it with PHP if necessary and I can detect in PHP when it is a directory or when not and we can also add something on the XML to detect the class="dirname".

I hope I've given sufficient information to understand me.

Thank you in advance!

8
  • possible duplicate of Multidimensional array iteration Commented Apr 19, 2011 at 8:44
  • @Gordon: I also need a recursive function in XSLT, is not what they ask on your link. Thank you anyway. :) Commented Apr 19, 2011 at 8:48
  • @Gordon: sorry, English is not my main language. The ul/li output list needs to be generated from an XML file. I added this: What I finally need is a multidimensional (don't know if is the exactly word) list with <ul /> and <li /> generated with XSLT 1.0 from a XML file Commented Apr 19, 2011 at 9:04
  • @udexter why do you have to do it with an XSLT? Why cant you just create the html output from the multidimensional php array? Commented Apr 19, 2011 at 9:07
  • @udexter: Why not swap multidimensional with recursive in your title? It's probably better to understand? It's just an idea? Commented Apr 19, 2011 at 9:10

2 Answers 2

1

Tunneling parameter:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:param name="pPath"/>
        <xsl:copy>
            <xsl:apply-templates select="node()|@*">
                <xsl:with-param name="pPath" select="$pPath"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="li[@class='dirname']">
        <xsl:param name="pPath"/>
        <xsl:call-template name="identity">
            <xsl:with-param name="pPath"
             select="concat($pPath,'/',normalize-space(text()[1]))"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template match="text()">
        <xsl:param name="pPath"/>
        <xsl:call-template name="text">
            <xsl:with-param name="pPath"
             select="concat($pPath,'/',normalize-space())"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template match="li[@class='dirname']/text()" name="text">
        <xsl:param name="pPath"/>
        <a href="{$pPath}">
            <xsl:value-of select="."/>
        </a>
    </xsl:template>
</xsl:stylesheet>

Output:

<ul>
    <li class="dirname">
        <a href="/dirname1">
            dirname1
        </a>
        <ul>
            <li class="dirname">
                <a href="/dirname1/Dirname2">
                    Dirname2
                </a>
                <ul>
                    <li class="dirname">
                        <a href="/dirname1/Dirname2/Dirname3">
                            Dirname3
                        </a>
                        <ul>
                            <li>
                                <a href="/dirname1/Dirname2/Dirname3/file1"
                                >file1</a>
                            </li>
                            <li>
                                <a href="/dirname1/Dirname2/Dirname3/file2"
                                >file2</a>
                            </li>
                            <li>
                                <a href="/dirname1/Dirname2/Dirname3/file3"
                                >file3</a>
                            </li>
                        </ul>
                    </li>
                    <li>
                        <a href="/dirname1/Dirname2/file4">file4</a>
                    </li>
                    <li>
                        <a href="/dirname1/Dirname2/file5">file5</a>
                    </li>
                    <li>
                        <a href="/dirname1/Dirname2/file6">file6</a>
                    </li>
                    <li class="dirname">
                        <a href="/dirname1/Dirname2/dirname4">
                            dirname4
                        </a>
                        <ul>
                            <li>
                                <a href="/dirname1/Dirname2/dirname4/file7"
                                >file7</a>
                            </li>
                            <li>
                                <a href="/dirname1/Dirname2/dirname4/file8"
                                >file8</a>
                            </li>
                        </ul>
                    </li>
                </ul>
            </li>
            <li>
                <a href="/dirname1/file9">file9</a>
            </li>
            <li>
                <a href="/dirname1/file10">file10</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="/file11">file11</a>
    </li>
    <li>
        <a href="/file12">file12</a>
    </li>
    <li>
        <a href="/file13">file13</a>
    </li>
</ul>
Sign up to request clarification or add additional context in comments.

6 Comments

@Alejandro: thank you for your XSLT. What is your XML input like? Thank you in advance!
I've tried with this input, but I don't get the same output: pastebin.com/Jj5gB2Nk
@udexter: I'm using the input you post. The new one you link it hasn't any @class equal to "dirname".
@Alejandro: Ah! That was the final needed output, what I need in HTML. I didn't know what was a nice structure to process it with XML to obtain that finally HTML. Do you suggest a better XML?
@udexter: Any schema will work as long as it has all the information... We all are using the one you post. If that is not the proper one, please update.
|
1

PHP part

function ulRenderer($dirs, $path = array()) {
    echo '<ul>';
    foreach ($dirs as $key => $value) {
        if (is_array($value)) {
            printf(
                '<li class="dirname"><a href="%s">%s</a>',
                implode('/', $path),
                $key
            );

            ulRenderer($value, array_merge(
                $path, array($key)
            ));
            echo '</li>';
        }
        else {
            printf(
                '<li><a href="%s/%s">%s</a></li>',
                implode('/', $path),
                $value, $value
            );
        }
    }
    echo '</ul>';
}

$dirs = array(
    "dirname1" => array(
        "dirname2" => array(
            "dirname3" => array(
                "0" => "file1",
                "1" => "file2",
                "2" => "file3"
            ),
            "0" => "file4",
            "1" => "file5",
            "2" => "file6",
            "dirname4" => array(
                "0" => "file7",
                "1" => "file8"
            )
        ),
        "0" => "file9",
        "1" => "file10"
    ),
    "0" => "file11",
    "1" => "file12",
    "2" => "file13"
);


ulRenderer($dirs);

XML/XSL part

dirs.xml

<?xml version="1.0" encoding="UTF-8" ?>
<root>
    <dir name="dirname1">
        <dir name="dirname2">
            <dir name="dirname3">
                <file>file1</file>
                <file>file2</file>
                <file>file3</file>
            </dir>

            <dir name="dirname4">
                <file>file4</file>
                <file>file5</file>
            </dir>

            <file>file6</file>
            <file>file7</file>
            <file>file8</file>
        </dir>

        <file>file11</file>
        <file>file12</file>
        <file>file13</file>
    </dir>
</root>

dirs.xslt

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="dir">
        <ul>
            <li>
                <a>
                    <xsl:attribute name="href">
                        <xsl:call-template name="path" />
                    </xsl:attribute>
                    <xsl:value-of select="@name" />
                </a>
                <xsl:apply-templates />
            </li>
        </ul>
    </xsl:template>

    <xsl:template match="file">
        <li>
            <a>
                <xsl:attribute name="href">
                    <xsl:call-template name="path" />
                </xsl:attribute>
                <xsl:value-of select="." />
            </a>
        </li>
    </xsl:template>

    <xsl:template name="path">
        <xsl:if test="parent::dir">
            <xsl:for-each select="ancestor::dir">
                <xsl:sort select="position()" order="ascending"/>
                <xsl:value-of select="@name" />
                <xsl:text>/</xsl:text>
            </xsl:for-each>
        </xsl:if>
        <xsl:choose>
            <xsl:when test="name() = 'dir'">
                <xsl:value-of select="@name" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="." />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

and php again

$dom = new DOMDocument;
$dom->load('dirs.xml');

$xsl = new DOMDocument;
$xsl->load('dirs.xslt', LIBXML_NOCDATA);

$xslt = new XSLTProcessor();
$xslt->importStylesheet($xsl);

echo $xslt->transformToXML($dom);

1 Comment

Thank you! It will be helpful when generating the XML structure. Now see if someone can help me with the XSLT part!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.