【问题标题】:PHP DOM Get Node Path from XML does not return tag namesPHP DOM从XML获取节点路径不返回标签名称
【发布时间】:2017-05-27 04:42:29
【问题描述】:

我正在尝试搜索一个 KML 文件(对于那些不知道的人,这是一个 XML 文件,其中包含用于在地图上标记线和多边形的 GPS 信息),其布局如下:

<kml xmlns="..." blah blah blah>
    <Document id="Layers">
        <name>Layers</name>
        <Snippet></Snippet>
        <description>Sample Location Data</description>
        <Folder id="Folder1">
            <name>The First Folder</name>
            <Snippet></Snippet>
            <description>Sample Folder</description>
            <Placemark id="ID_00000">
                <name>First Placemark</name>
                <Snippet></Snippet>
                <styleUrl>#PolyStyle00</styleUrl>
                <MultiGeometry>
                    <Polygon>
                        <extrude>0</extrude>
                        <altitudeMode>clampToGround</altitude>
                        <tesselate>1</tesselate>
                        <outerBoundaryIs>
                            <LinearRing>
                                <coordinates>INSERT A TONNE OF GPS COORDINATES HERE</coordinates>
                            </LinearRing>
                        </outerBoundaryIs>
                    </Polygon>
                </MultiGeometry>
            </Placemark>
        </Folder>
    </Document>
</kml>

这只是样本数据。实际文件为 15 MB。它还有更多文件夹,其中一些嵌套在其他文件夹中。

我想要做的是获取所有地标元素的列表。我当前的代码如下所示:

$data = file_get_contents(__DIR__ . './kmlFiles/lokations.kml');
$XML = new SimpleXMLElement($data);
$document = $XML->Document;
$dom = dom_import_simplexml($document);
$placemarks = $dom->getElementsByTagName('Placemark');
$placemarksArr = array();
foreach($placemarks as $dirKey => $dirVal) {
    $placemarksArr[count($placemarksArr)] = $dirVal->getNodePath();
}
var_dump($placemarksArr);

这行得通。但是,当我阅读我的 var_dump 时,我的第一个值如下:

[0]=> string(20) "/*/*/*[4]/*[4]"

例如,下一个地标嵌套在根“目录”中第二个文件夹内的文件夹内:

[1]=> string(19) "/*/*/*[5]/*[3]/*[4]"

然而,对我来说,我期望的输出应该是:

/XML/Document/Folder/Placemark

/XML/Document/Folder[0]/Placemark[0]

鉴于我在这个文件中只有不到 10,000 个地标,我更喜欢这样的解决方案,它不涉及我分解路径并为每个星号查找元素类型,然后在其父元素中找到该元素的适当实例。我的理解是 DOMNode:getNodePath() 会返回一个比人类在父节点中的位置更易读的 xpath。

我做错了吗?有没有更好的方法来检索我的地标的路径数组?

干杯。

【问题讨论】:

    标签: php xml dom xpath kml


    【解决方案1】:

    实际上/XML/Document/Folder/Placemark 是无效的。 XML 使用命名空间,因此您需要为其注册一个前缀并在 Xpath 中使用它。

    类似于/kml:XML/kml:Document/kml:Folder/kml:Placemark

    DOMNode::getNodePath() 没有要使用的前缀,因此它回退到 * - 它匹配任何元素节点。

    您可以使用 Xpath 查找有关节点的必要信息,以构建您自己的位置路径表达式。对于ancestor::*,将获取所有父元素直到文档节点。 count(preceding-sibling::Placemark) 将在当前节点之前计算所有具有相同父节点的 Placemark 节点。

    【讨论】:

    • 您好,感谢您的回复!我可以注册一个命名空间以使 /XML/Document/Folder/Placemark 有效还是不可能?另外,根据您的回复,我的理解是,如果我添加一个带有 kml 前缀的命名空间,那么我将不得不更改所有标签,以便我正在搜索的 Placemark 将从 更改为 对吗?我不想在我的文件中这样做,因为它们可能会定期更新,但我想我可以在 PHP 中这样做。我将缓存文件以删除我不需要的部分并减少客户端的运行时间,因此运行时不是一个大问题。
    • 不,Xpath 1.0 没有默认命名空间的概念。任何命名空间都必须使用前缀来引用。像*[local-name() = 'tag' and namespace-uri() = 'urn:namespace'] 这样的东西是可能的,但对此没有用。此外,您不能注册命名空间以供 DOM API 使用,只能用于 Xpath 表达式。无论如何,我不确定您要对位置路径做什么 - 您可能需要重新考虑这个概念。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多