【问题标题】:Searching an XML structure but modifying a node higher in the hierarchy搜索 XML 结构但修改层次结构中更高的节点
【发布时间】:2022-01-06 03:49:45
【问题描述】:

因此,这里以 MWE XML 为例

<manifest xmlns="http://iuclid6.echa.europa.eu/namespaces/manifest/v1"
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <general-information>
        <title>IUCLID 6 container manifest file</title>
        <created>Tue Nov 05 11:04:06 EET 2019</created>
        <author>SuperUser</author>
    </general-information>
    <base-document-uuid>f53d48a9-17ef-48f0-8d0e-76d03007bdfe/f53d48a9-17ef-48f0-8d0e-76d03007bdfe</base-document-uuid>
    <contained-documents>
        <document id="f53d48a9-17ef-48f0-8d0e-76d03007bdfe/f53d48a9-17ef-48f0-8d0e-76d03007bdfe">
            <type>DOSSIER</type>
            <name xlink:type="simple" 
                xlink:href="f53d48a9-17ef-48f0-8d0e-76d03007bdfe_f53d48a9-17ef-48f0-8d0e-76d03007bdfe.i6d"
                >Initial submission</name>
            <first-modification-date>2019-03-27T06:46:39Z</first-modification-date>
            <last-modification-date>2019-03-27T06:46:39Z</last-modification-date>
        </document>
    </contained-documents>
</manifest>

在这种情况下,我想找到一个属性 xlink:href 并将 name 标记替换为 xlink:href 引用的文件的内容 - 在本例中为 f53d48a9-17ef-48f0-8d0e-76d03007bdfe_f53d48a9-17ef -48f0-8d0e-76d03007bdfe.i6d(也是 XML 格式文件)。

目前我使用 simplexml 将其拉入一个对象,然后使用 xml2json 库将其转换为一个递归数组 - 但使用普通方法遍历它并没有给我修改父节点的方法..

我不确定如何备份层次结构 - 有什么建议吗??

【问题讨论】:

  • “目前我使用 simplexml 将其拉入对象,然后使用 xml2json 库将其转换为递归数组”——这听起来很糟糕;一旦你这样做了,你就抛弃了 PHP 的所有内置 XML 功能。查看the functionality SimpleXML actually provides,以及more complex but powerful DOM API
  • 会看看,但现在真的想拆开一个可怕的可怕的 XML 文档结构.. :) 所以我去这个地方的原因是我想把所有东西都塞进一个数组中待处理..
  • 看看 SimpleXML 和 DOM API - 我实际上不需要将东西保存在 XML 中,而且这两个库都没有提供我可以在数组处理程序下获得的功能 - 我必须自己编写搜索功能并以不同方式处理遍历结构..所以我将留在数组库中:)
  • 但话又说回来 - array_walk_recursive 实际上只提供单个键,所以这对我也没有帮助:)
  • 但这让我可以递归地遍历 XML 结构 :) stackoverflow.com/questions/17095484/…

标签: php arrays xml


【解决方案1】:

这就是我现在所处的位置 - xml2array (https://github.com/tamlyn/xml2json) 提供了一个数组数组,其中 XML 属性也被带入数组

<?php
include('./xml2json.php');

$arrayData = [];
$xmlOptions = array(
    "namespaceRecursive" => "True"
);

function &i6cArray(& $array){
    foreach ($array as $key => $value) {
        if(is_array($value)){
            //recurse the array of arrays
            $value = &i6cArray($value);
            $array[$key]=$value;
            print_r($value);
        } elseif ($key == '@xlink:href') {
            // we want to replace the element here with the ref'd file contents
            // So we should get name.content = file contents
            $tempxml = simplexml_load_file($value);
            $tempArrayData = xmlToArray($tempxml);
            $array['content']=$tempArrayData;
        } else {
            //do nothing (at least for now)
        }
    }
    return $array;
}

if (file_exists('manifest.xml')) {
    $xml = simplexml_load_file('manifest.xml');
    $arrayData = xmlToArray($xml,$xmlOptions);
    
    // walk array - we know the initial thing is an array
    $arrayData = &i6cArray($arrayData);
    
    //output result
    $jsonString = json_encode($arrayData, JSON_PRETTY_PRINT);
    file_put_contents('dossier.json', $jsonString);
} else {
    exit("Failed to open manifest.");
}

?>

因为我想删除 @xlink 属性,但不会死,否则我将插入一个“内容”值,该值将是引用的 XML 内容。

我仍然会链接以用某些东西替换整个“名称”键

【讨论】:

    【解决方案2】:

    在我们进入具体解决方案之前先了解一些背景知识:

    • 冒号前的名称部分是特定命名空间的本地别名,由xmlns 属性中的URI 标识。它们需要与非命名空间名称略有不同的处理;见this reference question for SimpleXML
    • PHP 的 SimpleXML 和 DOM 扩展都支持一种称为“XPath”的语言,它允许您根据父元素和/或内容搜索元素和属性。
    • DOM 是一个比 SimpleXML 更复杂的 API,但具有更强大的功能,尤其是在编写方面。您可以使用simplexml_import_dom()dom_import_simplexml() 函数在两者之间切换。

    在这种情况下,我们要查找所有xlink:href 属性。查看文件顶部的xmlns 属性,我们看到它们位于http://www.w3.org/1999/xlink 命名空间中。在 XPath 中,你可以用 [@attributename] 的语法说“有一个属性”,所以我们可以像这样使用 SimpleXML 和 XPath:

    $simplexml->registerXpathNamespace('xl', 'http://www.w3.org/1999/xlink');
    $elements_with_xlink_hrefs = $simplexml->xpath('//[@xl:href]');
    

    对于每一个,我们都需要属性值:

    foreach ( $elements_with_xlink_hrefs as $simplexml_element ) {
        $filename = (string)$simplexml_element->attributes('http://www.w3.org/1999/xlink')->href;
        // ...
    

    然后我们要加载该文件,并将其注入到文档中;使用 DOM 会更容易,但是必须“导入”节点以使其为正确的文档“拥有”,这很复杂。

        // load the other file
        $other_document = new DOMDocument;
        $other_document->load($filename);
        // switch to DOM and add it in place
        $dom_element = dom_import_simplexml($simplexml_element);
        $dom_element->appendChild(
            $dom_element->ownerDocument->importNode(
                $other_document->documentElement
            )
        );
    

    我们现在可以整理和删除“xlink”属性:

        $dom_element->removeAttributeNs('http://www.w3.org/1999/xlink', 'href');
        $dom_element->removeAttributeNs('http://www.w3.org/1999/xlink', 'type');
    

    完成后,我们可以将整个内容作为一个组合的 XML 文档输出:

    } // end of foreach loop
    echo $simplexml->asXML();
    

    【讨论】:

    • 很快就会尝试一下.. SimpleXML 和 DOM 的文档是 ..sparse.. :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    • 2020-01-04
    • 1970-01-01
    • 2021-09-29
    • 1970-01-01
    相关资源
    最近更新 更多