我有一个令人难以置信的任务。我有一个直截了当的饲料。出租的属性是精确的,它看起来像这样:
<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,并将所有不同的单元放置到一个属性中。所以新的Feed将如下所示:
<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>
有人可以帮我解决这个问题吗?非常感谢
答案 0 :(得分:1)
有更多选项可以获得您想要的结果。使用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的所有foreach
个节点中执行<ad>
,并且 - 对于每个节点 - 检索<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 demo 强>
附加说明:
在上面的脚本中,我假设每个属性名称都有唯一的long / lat。如果可以存在具有相同名称但长/纬度不同的属性,则必须不仅按名称查找节点,还要按纬度/经度查找节点。
我还假设您的结构样本在每个节点中都得到了尊重。否则,$node->getElementsByTagName( 'latitude' )->item(0)->nodeValue
之类的语法可能会失败,您必须将其替换为:
if( $node->getElementsByTagName( 'latitude' )->length )
{
$lat = $node->getElementsByTagName( 'latitude' )->item(0)->nodeValue;
}
以及->item(0)
语法的每个代码行。