dongyan1808 2016-03-28 19:13
浏览 38
已采纳

使用parent-child元素重新创建XML feed

I have a mind boggling task. I have a feed which is straight forward. Properties for rent to be precise and it looks something like this:

<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>

In the above example there is a single property with two different units. The only thing which is common for both is the name and latitude, longitude fields.

Now, I need to recreate this XML into the new one using PHP, and to place all of the different units to the one property. So the new feed will look like following:

<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>

Can somebody help me out with this? Many thanks

  • 写回答

1条回答 默认 最新

  • dsk95913 2016-03-28 20:43
    关注

    There are more options to obtain your desired result. With DOMDocument you can use importNode, or you can directly modify original XML.

    I will show you a method to create a completely new XML.

    First of all, you have to load existing XML in a DOMDocument object:

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

    Then create the destination DOMDocument object. For this, I use a generic <root> tag; you can replace it with your complete XML wrapping <ad> tags:

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

    Now, init a DOMXpath object for destination XML. DOMXPath permits to execute complex XML queries:

    $xpath = new DOMXPath( $dom );
    

    At this point, perform a foreach through all <ad> nodes of source XML and — for each node — retrieve <name> and <area> values:

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

    Now use DOMXPath to find if in destination XML there is already a <ad> node with <name> value = retrieved name:

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

    If the destination node is found, set its <units> as $child:

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

    Otherwise, create a new node adding base data from source, then set it as $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);
        }
    

    At this point, you have the correct $child node to add the <unit>:

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

    At the end of foreach() loop, you can print the obtained XML:

    echo $dom->saveXML();
    

    output:

    <?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>
    

    <kbd>eval.in demo</kbd>


    Additional notes:

    In script above, I assume that each property name has unique long/lat. If can exists properties with same name but different long/lat, you have to find node not only by name, but also by latitude/longitude.

    I assume also that your structure sample is respected in each node. Otherwise, syntax like $node->getElementsByTagName( 'latitude' )->item(0)->nodeValue can fails, and you have to replace it by:

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

    and so for each code line with ->item(0) syntax.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)