2

I know duplicate keys in array is not possible. There is an API that i send data to in XML format. The prosess is that i need to hold it in Array before i convert it to XML and send it to the API. The API only accepts the format i show you under. So this is my problem i need help with:

XML format API need (Preferred result):

<root>
  <id>FACE</id>
  <title>FACEBOOK NOVEMBER 2019</title>
  <agreement_id>REDP</agreement_id>
  <contact>Sidra</contact>
  <order_id>4715</order_id>
  <plan_no>417</plan_no>
  <insertion>
      <insertion_date>2019-10-08</insertion_date>
      <start_date>2019-10-08</start_date>
      <end_date>2019-10-09</end_date>
      <PO_number>150</PO_number>
      <price_row>
        <price_code>000</price_code>
        <gross>11111</gross>
      </price_row>
  </insertion>
  <insertion>
      <insertion_date>2019-10-09</insertion_date>
      <start_date>2019-10-09</start_date>
      <end_date>2019-10-10</end_date>
      <PO_number>152</PO_number>
      <price_row>
        <price_code>000</price_code>
        <gross>11111</gross>
      </price_row>
  </insertion>
  <type>method_name</type>
  <password>*******</password>
  <company_id>*******</company_id>
</root>

This i cannot find a solution for when having an Array, because the insertion block need to be identical like this.

Here is my solution for my request from converting multidimensional array to XML format:

static function addXMLData(\SimpleXMLElement $xml, array $data) {
    array_walk($data, function ($value, $key) use ($xml) {
        if (is_array($value)) {
            $child = $xml->addChild($key);
            self::addXMLData($child, $value);
        } else {
            $xml->addChild($key, $value);
        }
    });
}

static function createXML($data, $root = null) {
    $xml = new \SimpleXMLElement($root ? '<' . $root . '/>' : '<root/>');
    self::addXMLData($xml, $data);
    $dom = dom_import_simplexml($xml)->ownerDocument;
    $dom->encoding = "UTF-8";
    $dom->formatOutput = true;
    echo $dom->saveXML();
}

This is the array i send in from client:

$order_data = array([
    "id" => 'FACE',
    "title" => 'FACEBOOK NOVEMBER 2019',
    "agreement_id" => 'REDP',
    "contact" => "Sidra",
    "order_id" => 4715,  
    "plan_no" => 417,  
    "insertion" => [       
        "insertion_date" => '2019-10-08',
        "start_date" => '2019-10-08',
        "end_date" => "2019-10-09",
        "PO_number" => 150,
        "price_row" => [
            "price_code" => '000',
            "gross" => 11111
        ],
    ],
    "insertion" => [
            "insertion_date" => '2019-10-09',
            "start_date" => '2019-10-09',
            "end_date" => "2019-10-10",
            "PO_number" => 151,
            "price_row" => [
                "price_code" => '000',
                "gross" => 11111
            ],
        ]
]);
 echo "<pre>";
 print_r($order_data);
 die;

This result removes the duplicate array key and it will not work. How can i smart convert this to XML and keep the duplicate keys?

This is my complete function, sorry for a lot of code. $data_flatten is the array above. _request has the CreateXML method inside. Ive hardcoded the insertion "bulk"

public function create_order_direct($order_data) {

    $data_flatten = [];
    array_walk_recursive($order_data, function ($v, $k) use (&$data_flatten) {
        $data_flatten[$k] = $v;
    });
    // If present = replace
    // Else create new order with entries(insertion)
    if (!isset($data_flatten['order_id'])) {
        $data_flatten['order_id'] = "";
    }

    return $this->__request(__FUNCTION__, [
        "id" => $data_flatten['media_id'],
        "title" => $data_flatten['headline'],
        "agreement_id" => self::AGREEMENT_ID,
        "contact" => $data_flatten['client_contact'],
        "order_id" => $data_flatten['order_id'],
        "plan_no" => $data_flatten['plan_number'],
        "insertion" => [
                "insertion_date" => '2019-10-08',
                "start_date" => '2019-10-08',
                "end_date" => "2019-10-09",
                "PO_number" => 150,
                "price_row" => [
                    "price_code" => '000',
                    "gross" => 11111
                ]
        ],
        "insertions" => [
        [
            "insertion_date" => '2019-10-09',
            "start_date" => '2019-10-09',
            "end_date" => "2019-10-10",
            "PO_number" => 152,
            "price_row" => [
                "price_code" => '000',
                "gross" => 11111
            ],
    ]
    ]);
}









EDIT / UPDATE:

Thank you guys. I followed your advice and now added array inside an array for insertion block as you suggested. The result i have now looks like this:

<root>
  <id>FACE</id>
  <title>FACEBOOK NOVEMBER 2019</title>
  <agreement_id>REDP</agreement_id>
  <contact>Sidra</contact>
  <order_id>4715</order_id>
  <plan_no>417</plan_number>
  <insertion>
    <0>
      <insertion_date>2019-10-08</insertion_date>
      <start_date>2019-10-08</start_date>
      <end_date>2019-10-09</end_date>
      <PO_number>150</PO_number>
      <price_row>
        <price_code>000</price_code>
        <gross>11111</gross>
      </price_row>
    </0>
    <1>
      <insertion_date>2019-10-09</insertion_date>
      <start_date>2019-10-09</start_date>
      <end_date>2019-10-10</end_date>
      <PO_number>151</PO_number>
      <price_row>
        <price_code>000</price_code>
        <gross>11111</gross>
      </price_row>
    </1>
  </insertion>
  <type>method_name</type>
  <password>********</password>
</marathon>

The only problem i see now is that the XML add numbers for the multidimensional array. And i need to wrap multiple <insertion> block where the numeric key starts. How can i do that?

This is what i want:

<root>
  <id>FACE</id>
  <title>FACEBOOK NOVEMBER 2019</title>
  <agreement_id>REDP</agreement_id>
  <contact>Sidra</contact>
  <order_id>4715</order_id>
  <plan_no>417</plan_number>
  <insertion>
      <insertion_date>2019-10-08</insertion_date>
      <start_date>2019-10-08</start_date>
      <end_date>2019-10-09</end_date>
      <PO_number>150</PO_number>
      <price_row>
        <price_code>000</price_code>
        <gross>11111</gross>
      </price_row>
  </insertion>
  <insertion>
      <insertion_date>2019-10-09</insertion_date>
      <start_date>2019-10-09</start_date>
      <end_date>2019-10-10</end_date>
      <PO_number>151</PO_number>
      <price_row>
        <price_code>000</price_code>
        <gross>11111</gross>
      </price_row>
  </insertion>
  <type>method_name</type>
  <password>********</password>
</marathon>
Ali Durrani
  • 333
  • 2
  • 11

1 Answers1

0

You'll want to use a slightly different structure to avoid duplicate keys:

So instead of:

<key />
<key />

You would use:

<keys>
  <key />
  <key />
</keys>

http://lists.xml.org/archives/xml-dev/201504/msg00019.html

And at that point if your conversion function doesn't automatically parse that into an array, you can do it manually by giving each new a numerical key instead of an associative one and you're all set.

So if dom child quantity > 1, then loop and key = i+1

Citizen
  • 12,430
  • 26
  • 76
  • 117
  • @AliDurrani For xml you still want to use and not numeric keys. You want to switch to numeric keys on import. But the benefit of my answer is that now you can detect it easily by counting child items in the dom. – Citizen Nov 27 '18 at 21:02
  • do you have any link/tutorial i can read that can solve my problem. What you are saying makes sence but i need a little help with solving it. – Ali Durrani Nov 28 '18 at 08:21
  • @AliDurrani https://www.w3schools.com/php/php_ref_simplexml.asp check out hasChildren() and getChildren() – Citizen Nov 28 '18 at 19:13