如何完全解析 XML 文档中的所有内容?

Posted

技术标签:

【中文标题】如何完全解析 XML 文档中的所有内容?【英文标题】:How to fully parse everything in an XML document? 【发布时间】:2022-01-03 09:00:28 【问题描述】:

这个问题被问了很多,但不幸的是,发布的答案对我不起作用。

我正在尝试为具有自己的 DTD 等的文档解析自定义 XML。我的目标是从文档的 XML 标记生成 html 文档。出于所有实际目的,XML 已给出且不能修改。

生成 HTML 很容易 - 将 XML 放入程序中以便我可以使用它似乎是这里具有挑战性的部分。我尝试了许多不同的技术,但在某些情况下它们似乎都失败了。

php 的简单 XML 解析器本身不包含子属性(以及许多其他内容),例如$xml = simplexml_load_string($xmlFile); 带有 json 编码/解码的 PHP 简单 XML 解析器无法处理包含属性的子节点,例如json_decode(json_encode($xml)) This solution I've found 是唯一可以处理具有属性的子节点的,但它不尊重 CDATA 并且基本上屠宰了整个文件 简单地转换为数组似乎是合理的,但也无法处理包含属性的子节点,例如$xml = simplexml_load_string($file); $array = (array)$xml; DOM 文档完全混乱,只生成一堆格式化的纯文本。 其他一般问题包括不恰当地将子节点脱离上下文。使用 CDATA 主要有助于解决此问题,但处理此问题的解决方案无法处理其他问题。

我本来打算把XML解析成一个数组,理论上是可以的,但是到目前为止我还没有成功。

XML 大约有 32,000 行。要求是我需要捕获所有内容。这包括所有节点的所有属性和所有节点的所有内容。这包括从字面上捕获 CDATA。令人惊讶的是,每个主要的解析解决方案都排除了 something

没有专门编写一个自定义程序来解析这个特定的 XML,有没有解决方案或方法可以可靠地将所有内容捕获到一个数组中(或某种允许遍历整个内容的机制)?

这里是完整的 XML 文件供参考:https://interlinked.us/files/xml.txt

我会指出一些事情:

我正在通过在某些标签周围添加 CDATA 来预处理文件:
$xmlFile = str_replace("<literal>", "<![CDATA[<literal>", $xmlFile);
$xmlFile = str_replace("</literal>", "</literal>]]>", $xmlFile);
$xmlFile = str_replace("<replaceable>", "<![CDATA[<replaceable>", $xmlFile);
$xmlFile = str_replace("</replaceable>", "</replaceable>]]>", $xmlFile);

这是因为最终目标只是将这些替换为 &lt;span&gt;&lt;b&gt;&lt;code&gt; 或类似的东西,我不希望这些特定节点被解析为 XML。很容易。然而,这也需要遵守 CDATA。

以下是在大多数解决方案中通常无法正确解析的 XML 示例:
<application name="Reload" language="en_US">
        <synopsis>
            Reloads an Asterisk module, blocking the channel until the reload has completed.
        </synopsis>
        <syntax>
            <parameter name="module" required="false">
                <para>The full name(s) of the target module(s) or resource(s) to reload.
                If omitted, everything will be reloaded.</para>
                <para>The full names MUST be specified (e.g. <literal>chan_iax2</literal>
                to reload IAX2 or <literal>pbx_config</literal> to reload the dialplan.</para>
            </parameter>
        </syntax>
        <description>
            <para>Reloads the specified (or all) Asterisk modules and reports success or failure.
            Success is determined by each individual module, and if all reloads are successful,
            that is considered an aggregate success. If multiple modules are specified and any
            module fails, then FAILURE will be returned. It is still possible that other modules
            did successfully reload, however.</para>
            <para>Sets <variable>RELOADSTATUS</variable> to one of the following values:</para>
            <variablelist>
                <variable name="RELOADSTATUS">
                    <value name="SUCCESS">
                        Specified module(s) reloaded successfully.
                    </value>
                    <value name="FAILURE">
                        Some or all of the specified modules failed to reload.
                    </value>
                </variable>
            </variablelist>
        </description>
    </application>

解析失败是SUCCESSFAILURE在解析后的数组中无处可寻!这似乎是因为大多数 XML 解析器忽略了叶节点中的属性。

另一个可能的要求是叶子节点本身只包含文本并且包含在包含其他文本的父节点中,不应将其解析为单独的元素。例如,在上面的输出中,请注意variable 标记以多种方式使用。它用作类似于literalreplaceable 的格式化程序,但也是它自己的节点类型,如variablelist

解决方案需要包含在单个脚本中(但我可以安装 Debian 软件包)。我最熟悉如何在 PHP 中做这种事情,但对其他工具持开放态度,特别是如果它们是 POSIX 可移植的。

最终,我不是在寻找最优雅的解决方案或输出,而是至少可以工作并完全捕捉所有内容的东西。我似乎已经用尽了内置的 PHP 工具和常见答案 - 关于如何解决这个问题的任何建议?

同样,目标是从中生成网页的 HTML。因此,我需要所有属性和值,以便我可以在上下文中正确构建网页。

到目前为止我发现的最好的是xmlObjToArr()in the comments on the PHP page,它实际上可以运行。但我检查了一下,它至少通过了叶节点属性测试,所以我要看看是否还有其他遗漏。所有其他解决方案都会立即执行,而在空闲服务器上运行需要 45-60 秒,但如果这就是解析 XML 所需要的,我猜它就是这样。

【问题讨论】:

我认为您应该选择一个 XML 解析器并尝试使用您的文档。如果某些东西不起作用,作为一个关于bthat 缺陷的特定 问题(minimal reproducible example)。如果无法克服限制,则继续使用另一个 XML 解析器。就目前而言,我觉得这个问题太宽泛了。 “大多数 XML 解析器都会忽略叶节点中的属性”——我很难接受事实确实如此。我认为您的问题应该包含演示这一点的代码,以便有人可以指出您做错了什么,或帮助确定替代方案。 DOM(甚至 SimpleXML)完全解析 XML。听起来您正在尝试使用一些自动转换。使用 DOM/SimpleXML Api 方法读取 XML。 您的问题没有达到您的目标。您想从 XML 中的数据生成什么? 【参考方案1】:

将 xml 解析为完全满足我需求的数组的最简单方法是:

$array = json_decode(json_encode(simplexml_load_string($xml)), 1);

【讨论】:

那是调试输出的序列化,会丢失很多信息。 另外,我已经尝试过了,但它会丢失叶节点上的属性

以上是关于如何完全解析 XML 文档中的所有内容?的主要内容,如果未能解决你的问题,请参考以下文章

PHP处理XML文档,没有CDATA部分数据处理

xml_dom解析

如何用Dom4j获取CDATA结点内容

XML 解析

2 XML 以及XML解析

java的xml的解析方式有啥,他们的解析流程是怎么样的,有啥区别