正在使用父子元素重新创建XML提要


Recreating XML feed with parent - child elements

我有一项令人难以置信的任务。我有一个直接的提要。确切地说,出租的房产看起来像这样:

<ad>
<name>Property 1</name>
<latitude>29.723085</latitude>
<longitude>-95.66024</longitude>
<area>2000</area>
</ad>
<ad>
<name>Property 1</name>
<latitude>29.723085</latitude>
<longitude>-95.66024</longitude>
<area>2500</area>
</ad>

在上面的示例中,有一个具有两个不同单元的属性。两者唯一的共同点是名称和纬度、经度字段。

现在,我需要使用PHP将这个XML重新创建到新的XML中,并将所有不同的单元放置到一个属性中。因此,新的提要将如下所示:

<ad>
<property_name>Property 1</property_name>
<latitude>29.723085</latitude>
<longitude>-95.66024</longitude>
<units>
    <unit>
       <area>2000</area>
    </unit>
    <unit>
       <area>2500</area>
    </unit>
</units>
</ad>

有人能帮我吗?非常感谢

有更多选项可以获得您想要的结果。使用DOMDocument可以使用importNode,也可以直接修改原始XML。

我将向您展示一种创建全新XML的方法。

首先,您必须在DOMDocument对象中加载现有的XML:

$src = new DOMDocument();
libxml_use_internal_errors(1);
$src->loadXML( $xml );

然后创建目标DOMDocument对象。为此,我使用了一个通用的<root>标签;您可以将其替换为完整的XML包装<ad>标签:

$dom = new DOMDocument();
libxml_use_internal_errors(1);
$dom->loadXML( '<root></root>' );
$dom->formatOutput = True;
$root = $dom->getElementsByTagName( 'root' )->item(0);

现在,为目标XML初始化一个DOMXpath对象。DOMXPath允许执行复杂的XML查询:

$xpath = new DOMXPath( $dom );

此时,通过源XML的所有<ad>节点执行foreach,并为每个节点检索<name><area>值:

foreach( $src->getElementsByTagName( 'ad' ) as $node )
{
    $name = $node->getElementsByTagName( 'name' )->item(0)->nodeValue;
    $area = $node->getElementsByTagName( 'area' )->item(0)->nodeValue;

现在使用DOMXPath查找目标XML中是否已经存在<ad>节点,其<name>值=检索名称:

    $found = $xpath->query( '//ad[name[.="'.$name.'"]]' );

如果找到目的节点,则将其<units>设置为$child:

    if($found->length)
    {
        $child = $found->item(0)->getElementsByTagName('units')->item(0);
    }

否则,创建一个添加源基础数据的新节点,然后将其设置为$child:

    else
    {
        $lat  = $node->getElementsByTagName( 'latitude' )->item(0)->nodeValue;
        $long = $node->getElementsByTagName( 'longitude' )->item(0)->nodeValue;
        $child = $dom->createElement( 'ad' );
        $child->appendChild( $dom->createElement( 'name', $name ) );
        $child->appendChild( $dom->createElement( 'latitude', $lat ) );
        $child->appendChild( $dom->createElement( 'longitude', $long ) );
        $child->appendChild( $dom->createElement( 'units' ) );
        $root->appendChild( $child );
        $child = $child->getElementsByTagName('units')->item(0);
    }

此时,您有了正确的$child节点来添加<unit>:

    $unit = $dom->createElement( 'unit' );
    $unit->appendChild( $dom->createElement( 'area', $area ) );
    $child->appendChild( $unit );
}

foreach()循环结束时,您可以打印获得的XML:

echo $dom->saveXML();

输出:

<?xml version="1.0"?>
<root>
  <ad>
    <name>Property 1</name>
    <latitude>29.723085</latitude>
    <longitude>-95.66024</longitude>
    <units/>
    <unit>
      <area>2000</area>
    </unit>
    <unit>
      <area>2500</area>
    </unit>
  </ad>
</root>

eval.in演示


附加说明:

在上面的脚本中,我假设每个属性名称都有唯一的long/lat。若可以存在名称相同但长度/纬度不同的属性,则必须不仅按名称,而且按纬度/经度查找节点。

我还假设您的结构示例在每个节点中都受到尊重。否则,像$node->getElementsByTagName( 'latitude' )->item(0)->nodeValue这样的语法可能会失败,您必须将其替换为:

if( $node->getElementsByTagName( 'latitude' )->length )
{
    $lat = $node->getElementsByTagName( 'latitude' )->item(0)->nodeValue;
}

对于具有CCD_ 23语法的每个代码行也是如此。