You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP合并房产API返回的XML文件:解决重复XML声明与结构合法性问题

Hey there! Let's break down your problem and fix this step by step. The core issue here is that you're appending full XML documents (each with their own declaration and root <property> tag) into a single file, which makes it invalid XML right off the bat. Your merge attempt fails because DOMDocument can't parse that messy file, plus you've got a couple of syntax errors in your DOM manipulation code.

First, Let's Fix the Merge Code Errors (For Existing Invalid Files)

Your merge script has two critical mistakes:

  1. DOMNodeList (the result of getElementsByTagName()) doesn't have a property() method — you need to use item() to access nodes by index.
  2. The all_properties_full.xml is invalid XML (multiple declarations and root nodes), so DOMDocument::load() will choke on it before you even start merging.

To salvage the invalid file, you'd first need to clean it up:

  • Remove all instances of <?xml version="1.0" encoding="utf-8"?>
  • Wrap all remaining <property> nodes in a single <properties> tag

But this is a workaround. Let's go for the cleaner, more efficient solution that avoids creating an invalid file in the first place.

Better Approach: Build Valid XML Directly While Fetching Properties

Instead of appending raw XML responses to a file, we can use PHP's DOM extension to build our final valid XML document incrementally as we fetch each property. Here's how to modify your getProperties() method:

public function getProperties($client_id) {
    // Load authentication token (same as before)
    $token_storage = fopen('token.txt', 'r') or die("Unable to open file!");
    $token = trim(fread($token_storage, filesize("token.txt")));
    fclose($token_storage);

    // Initialize our final valid XML document
    $finalDoc = new DOMDocument('1.0', 'utf-8');
    $finalDoc->formatOutput = true; // Makes output human-readable

    // Create root <properties> node (or load your template if preferred)
    $propertiesRoot = $finalDoc->createElement('properties');
    $finalDoc->appendChild($propertiesRoot);

    // Fetch list of property IDs (same as original logic)
    $url = "http://webservices.vebra.com/export/".$this->_datafeedid."/v".$this->_version."/branch/{$client_id}/property";
    $headers = array (
        "Content-type: application/xml",
        "Connection: close",
        "Authorization: Basic ".base64_encode($token)
    );

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $all_properties_id_only = curl_exec($ch);
    file_put_contents ('./all_properties_id_only.xml', $all_properties_id_only);
    curl_close($ch);

    $xml=simplexml_load_file("./all_properties_id_only.xml") or die("Error: Cannot create object");
    $count = 0;

    // Reuse curl handle for better performance
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    foreach($xml->children() as $property) {
        $count++;
        echo "count = " .$count." property = ".$property->prop_id."<br>" ;
        $propertyId = (string)$property->prop_id;
        echo $propertyId . '<br>';

        // Fetch single property XML
        $propertyUrl = "http://webservices.vebra.com/export/".$this->_datafeedid."/v".$this->_version."/branch/{$client_id}/property/{$propertyId}";
        curl_setopt($ch, CURLOPT_URL, $propertyUrl);
        $propertyXmlResponse = curl_exec($ch);

        // Load single property XML into temporary DOM
        $tempDoc = new DOMDocument();
        libxml_use_internal_errors(true); // Suppress minor parsing warnings
        $tempDoc->loadXML($propertyXmlResponse);
        libxml_clear_errors();

        // Grab the <property> node and import it to our final document
        $propertyNode = $tempDoc->getElementsByTagName('property')->item(0);
        if ($propertyNode) {
            $importedNode = $finalDoc->importNode($propertyNode, true);
            $propertiesRoot->appendChild($importedNode);
        }
    }

    curl_close($ch);

    // Save the final valid XML file
    $finalDoc->save('./merged.xml');
    echo "Successfully generated valid merged.xml!";
}

Key Improvements Here:

  • No invalid intermediate files: We skip creating the messy all_properties_full.xml entirely, building the valid document step by step.
  • Reusable curl handle: Initializing curl once instead of per property boosts performance.
  • Safe DOM node handling: Using importNode() ensures we properly move nodes between documents without breaking XML structure.
  • Human-readable output: formatOutput = true makes the final XML easy to debug (remove this if you need compact output).

Using Your Template File Instead

If you want to start with your properties_template.xml instead of creating the root node from scratch, replace the initialization section with this:

// Load template and prepare root node
$finalDoc = new DOMDocument('1.0', 'utf-8');
$finalDoc->formatOutput = true;
$finalDoc->load('./properties_template.xml');
$propertiesRoot = $finalDoc->getElementsByTagName('properties')->item(0);
// Remove the dummy <property> node from the template
if ($propertiesRoot->firstChild) {
    $propertiesRoot->removeChild($propertiesRoot->firstChild);
}

Why Your Original Merge Code Failed

For learning purposes, here's a quick recap:

  • $doc1->getElementsByTagName('properties')->property(0) → Should be $doc1->getElementsByTagName('properties')->item(0)
  • $properties2 = $properties2->property($i) → Should be $propertyNode = $properties2->item($i)
  • Even after fixing those, $doc2->load('./all_properties_full.xml') would fail because the file is invalid XML. The approach above avoids this entirely.

内容的提问来源于stack exchange,提问作者SONewb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 17:07:46