Как определить пройденные XPath при запросе всех дочерних узлов? - PullRequest
3 голосов
/ 22 декабря 2010

У меня есть XML-документ, который представляет структуру каталогов.Каталоги представлены как <directory_name>, а файлы представлены как <file name="my_file.txt"/>.

Например:

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

Я хочу выполнить запрос XPath, чтобы получить все узлы <file>,но я также хочу знать путь к каталогу для каждого файла (т. е. имя тега каждого родительского узла) - есть ли простой способ сделать это с помощью XPath, или мне нужно будет выполнить рекурсивный обход дерева XML после того, как я проанализирую его в PHP

Ответы [ 2 ]

2 голосов
/ 22 декабря 2010

Следующее выражение XPath 2.0 :

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

при сравнении с предоставленным документом XML :

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

выдает искомый правильный результат :

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

Если вы не можете использовать XPath 2.0, вы не сможете получить искомый результат только с выражением XPath 1.0 .

Затем для получения результата необходимо использовать язык программирования, на котором размещается XPath (например, XSLT, C #, php, ...).

Вот решение XSLT 1.0:

<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>

когда это преобразование применяется к тому же XML-документу, получается тот же правильный результат :

home/mysite/www/images/logo.gif
home/mysite/www/index.html
home/mysite/www/about_us.html
0 голосов
/ 22 декабря 2010

Вы также можете попробовать это

<?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'));

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...