开发者

How do I determine the XPaths traversed when I query all child nodes?

开发者 https://www.devze.com 2023-01-31 16:23 出处:网络
I have an XML document that represents a directory structure. Directories are represented like <directory_name> and files are represented lik开发者_如何学Ce <file name=\"my_file.txt\"/>.

I have an XML document that represents a directory structure. Directories are represented like <directory_name> and files are represented lik开发者_如何学Ce <file name="my_file.txt"/>.

For example:

<xml>
    <home>
        <mysite>
            <www>
                <images>
                    <file name="logo.gif"/>
                </images>
                <file name="index.html"/>
                <file name="about_us.html"/>
            </www>
        </mysite>
    </home>
</xml>

I want to run an XPath query to get all the <file> nodes, but I also want to know the directory path to each file (i.e each parent node's tag name) - is there an easy way to do this with XPath, or will I need to do recursive traversal of the XML tree after I parse it in PHP?


The following XPath 2.0 expression:

   //file/concat(string-join(ancestor::*[parent::*]
                                   /concat(name(.), '/'),
                            ''),
                 @name, '&#xA;'
                 )

when evaluated against the provided XML document:

<xml>
    <home>
        <mysite>
            <www>
                <images>
                    <file name="logo.gif"/>
                </images>
                <file name="index.html"/>
                <file name="about_us.html"/>
            </www>
        </mysite>
    </home>
</xml>

produces the wanted, correct result:

home/mysite/www/images/logo.gif
 home/mysite/www/index.html
 home/mysite/www/about_us.html

In case you cannot use XPath 2.0, it isn't possible to produce the wanted result only with an XPath 1.0 expression.

Then the programming language that is hosting XPath (such as XSLT, C#, php,...) must be used to produce the result.

Here is an XSLT 1.0 solution:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="file">
   <xsl:for-each select="ancestor::*[parent::*]">
     <xsl:value-of select="concat(name(),'/')"/>
   </xsl:for-each>
   <xsl:value-of select="concat(@name, '&#xA;')"/>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

when this transformation is applied on the same XML document, the same correct result is produced:

home/mysite/www/images/logo.gif
home/mysite/www/index.html
home/mysite/www/about_us.html


You can also try this

<?php 

$dom = new DOMDocument();
$dom->loadXML($xml);

$xpath = new DOMXPath($dom);
$arrNodes = $xpath->query('//file');
foreach($arrNodes as $node) {

$tmpNode = $node->parentNode;
$arrPath = array();
while ($tmpNode->parentNode) {
    $arrPath[] = $tmpNode->tagName;     
    $tmpNode = $tmpNode->parentNode;
}
unset($arrPath[count($arrPath)-1]); 
printf('%s/%s<BR>',implode('/',array_reverse($arrPath)),$node->getAttribute('name'));

}
0

精彩评论

暂无评论...
验证码 换一张
取 消