如果已有内容,我如何获取xml标记的内部文本?

时间:2012-12-16 03:40:07

标签: php xml arrays

以下是我正在使用的示例xml:

<contact id="43956">
 <personal>
      <name>
           <first>J</first>
           <middle>J</middle>
           <last>J</last>
           Some text...
      </name>
      <title>Manager</title>
      <employer>National</employer>
      <dob>1971-12-22</dob>
 </personal>
</contact>

我得到了Some text...,但现在我需要我的代码来阅读整个xml文档。它也没有读取xml中的值...因为你可以说我以前从未使用过XMLReader

这就是我得到的:

Array ( [contact] => Array ( [id] => 43956 [value] => some sample value ) [first] => [middle] => [last] => [#text] => Some text... [name] => [title] => [employer] => [dob] => [personal] => )

以下是我现在的代码:

function xml2array($file, array $result = array()) {
$lastElementNodeType = '';
$xml = new XMLReader();
if(!$xml->open($file)) {
    die("Failed to open input file");
}
while($xml->read()) {
    switch ($xml->nodeType) {
        case $xml::END_ELEMENT:
            $lastElementNodeType = $xml->nodeType;
        case $xml::TEXT:
            $tag = $xml->name;
            if($lastElementNodeType == 15) {
                $result[$tag] = $xml->readString();                 
            }
        case $xml::ELEMENT:
            $lastElementNodeType = $xml->nodeType;
            $tag = $xml->name;
            if($xml->hasAttributes) {
                while($xml->moveToNextAttribute()) {
                    $result[$tag][$xml->name] = $xml->value;
                }
            }
    }
}
print_r($result);
}

我想过让这个函数递归,但是当我尝试它时,它让数组变得非常混乱。

我有一个版本,但它仍然没有输出J中的first等等:

function xml2assoc($xml) { 
$tree = null; 
while($xml->read()) 
    switch ($xml->nodeType) { 
        case XMLReader::END_ELEMENT: return $tree; 
        case XMLReader::ELEMENT: 
            $node = array('tag' => $xml->name, 'value' => $xml->isEmptyElement ? '' : xml2assoc($xml)); 
            if($xml->hasAttributes) 
                while($xml->moveToNextAttribute()) 
                    $node['attributes'][$xml->name] = $xml->value; 
            $tree[] = $node; 
        break; 
        case XMLReader::TEXT: 
        case XMLReader::CDATA: 
            $tree .= $xml->value; 
    } 
return $tree; 
}

1 个答案:

答案 0 :(得分:0)

取1

我认为您需要做的是保存最近节点的类型,或者至少保存最后一个节点,以便进行测试。简而言之,至少在您的示例XML中展示它时,您将遇到ELEMENT_END节点类型,TEXT节点类型,其中包含您正在查找的文本,然后是另一个ELEMENT_END节点类型{1}}节点类型。

所以你需要一个case $xml::TEXT,你还需要保存上一个节点类型,以便你的解析器知道,在正常情况下它应该是期待一个新的{{ 1}}事件或ELEMENT事件,但已收到TEXT。这将是您使用END_ELEMENT将文本捕获到临时变量所需的信号,并将其保存以用于您的目的,或等待查看下一个节点是否也是readString()此时您可以保存并清除临时变量。

拿2

现在我们知道了你希望最终得到的更多信息(即,因为你想要捕获整棵树而不仅仅是捕获整个树的特定信息),我建议你坚持使用递归版本功能。我稍微修改了你的那个(请参阅TEXT和CDATA案例进行主要的实质性修改)。

ELEMENT_END

这种情况下的输出看起来像:

function xml2assoc($xml)
{
    $tree = null;
    while($xml->read())
    {
        switch ($xml->nodeType)
        {
            case XMLReader::END_ELEMENT:
                return $tree;
            case XMLReader::ELEMENT: 
                $node = array('tag' => $xml->name, 'value' => $xml->isEmptyElement ? '' : xml2assoc($xml));
                if($xml->hasAttributes)
                    while($xml->moveToNextAttribute()) 
                        $node['attributes'][$xml->name] = $xml->value; 
                $tree[] = $node;
                break;
            case XMLReader::TEXT:
                $tree["text"] = $xml->value;
                break;
            case XMLReader::CDATA:
                $tree["cdata"] = $xml->value;
                break;
        }
    }
    return $tree;
}

我认为这是你想要的小编辑,但我们真的只是在这里重新发明轮子。我希望你需要解析的XML不是特别大。