通过复杂的 SimpleXMLElement 进行复杂循环

Complex Loop through a complex SimpleXMLElement

我需要从 XML 中保存一些值。

第一步 - 我得到了结构:

 $xml = $dom_xml->saveXML();
 $xml_ = new \SimpleXMLElement($xml);
 dd($xml_);

这里TextFrame有8个数组。他们每个人都有PathPointType,其中有 还有 4 个数组,每个数组有 3 个属性。我需要每个 TextFrame 的这些属性。

我可以获得,例如,Anchor这样做的价值:

$res = $xml_
        ->Spread
        ->TextFrame
        ->Properties
        ->PathGeometry
        ->GeometryPathType
        ->PathPointArray
        ->PathPointType
        ->attributes();
    dd($res['Anchor']);

(顺便说一句:还有更漂亮的方法吗?)

但问题是 - 如何遍历所有数组并分别为每个数组保存值?

我假设这里必须是一个多维 foreach 循环和 for 循环?

还是使用 DOMDocument 更好?

看起来好像您是从 DOMDocument 开始的(因为您正在使用 $dom_xml->saveXML() 生成 XML),继续使用它可能更容易,并且它也有一些简单的获取详细信息的功能。

使用getElementsByTagName()可以让您从起点获取具有特定标签名称的元素列表,因此从$dom_xml开始,获取所有<TextFrame>元素。然后 foreach() 遍历此列表并使用此元素作为起点,使用 getElementsByTagName("PathPointType") 获取嵌套的 <PathPointType> 元素。此时,您可以对 <PathPointType> 元素中需要的每个属性使用 getAttribute("Anchor")...

$textFrames = $dom_xml->getElementsByTagName("TextFrame");

foreach ( $textFrames as $frame )   {
    $pathPointTypes = $frame->getElementsByTagName("PathPointType");
    foreach ( $pathPointTypes as $type )    {
        echo $type->getAttribute("Anchor").PHP_EOL;
    }
}

编辑

您可以扩展代码以构建框架数组,然后构建其中的锚点。此代码还将锚点存储在关联数组中,这样如果您添加其他属性,您可以在此处添加它们(如果不需要另一层细节,则将其删除)...

$frames =[];
foreach ( $textFrames as $frame )   {
    $anchors = [];
    $pathPointTypes = $frame->getElementsByTagName("PathPointType");
    foreach ( $pathPointTypes as $type )    {
        $anchors[] = ['Anchor' => $type->getAttribute("Anchor")];
    }
    $frames[] = $anchors;
}

此外,如果您有某种识别框架的方法,您也可以在该级别创建一个关联数组...

$frames[$frameID] = $anchors;

作为 的补充,我想我会展示使用 SimpleXML 时相同循环的外观。

首先,请注意,如果您出于任何原因想要在 DOM 和 SimpleXML 之间切换,则无需将 XML 转换为字符串并返回,您可以使用 simplexml_import_dom 只是换出接口:

 $sxml = simplexml_import_dom($dom_xml);

接下来我们需要 TextFrame 个元素;我们可以显式地遍历结构,就像你之前做的那样:

$textFrames = $sxml->Spread->TextFrame;

或者我们可以使用 XPath 在当前节点中搜索匹配的标签名称(. 是当前元素,// 表示 "any descendant":

$textFrames = $sxml->xpath('.//TextFrame');

第一个会给你一个 SimpleXMLElement 对象,第二个会给你一个数组,但无论哪种方式,你都可以使用 foreach 来完成匹配。

这次我们肯定想要一个 XPath 表达式来获取 PathPointType 节点,以避免所有我们不感兴趣的级别的嵌套循环:

foreach ( $textFrames as $frame )   {
    $pathPointTypes = $frame->xpath('.//PathPointType');
    foreach ( $pathPointTypes as $type )    {
        echo $type['Anchor'] . PHP_EOL;
    }
}

请注意,您不需要调用 $type->attributes();除非你正在处理名称空间,否则你只需要获取一个属性就是 $node['AttributeName']。请注意,虽然 SimpleXML 中的属性是对象,因此您通常希望将它们强制为带有 (string)$node['AttributeName'].

的字符串

举最后一个例子,你可能会有这样的事情:

$frames = [];
foreach ( $sxml->Spread->TextFrame as $frame )   {
    $anchors = [];
    $pathPointTypes = $frame->xpath('.//PathPointType');
    foreach ( $pathPointTypes as $type )    {
        $anchors[] = ['Anchor' => (string)$type['Anchor']];
    }
    $frames[] = $anchors;
}