With this data (which is generated by services itself), the values of the array "hej" is not parsed properly.

<?xml version="1.0" encoding="utf-8"?>
<node>
<type>article</type>
<title>lala</title>
<hej is_array="true">
<item>1</item>
<item>23</item>
<item><bla>4</bla></item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
</hej>
</node>

The result is:

array (
  'type' => 'article',
  'title' => 'lala',
  'hej' => 
  array (
    0 => NULL,
    1 => NULL,
    2 => 
    array (
      'bla' => '4',
    ),
    3 => NULL,
    4 => NULL,
    5 => NULL,
    6 => NULL,
    7 => NULL,
  ),
)

I.e. the values of the "hej" array are all NULL.

Comments

esbenvb’s picture

Here's a patch.

IMPORTANT: When porting the patch to the GIT repo, follow the instructions here:
http://drupal.org/user/989064

marcingy’s picture

Priority: Major » Normal
Status: Patch (to be ported) » Needs work

I not reviewed the code but the patch does not meet drupals coding standards.

esbenvb’s picture

No shit sherlock :)

None of the code in the Services module meets the Drupal Coding standards. To make the patch and the new code look most readable in the context of the RESTServer.inc file, i chose to use the same indentation method as already used in the file - if I had used proper indentation, it would have looked like a mess next to the other code and probably someone else would have complained about that...

esbenvb’s picture

Status: Needs work » Needs review

Bumped status

marcingy’s picture

Status: Needs review » Needs work

lol, I have just looked at the code and this function sucks for standards so yeah lets leave that for a different issue! So I am wondering if we actually want to keep the call the function in a recursive manner. So atm we do

foreach ($node->children() as $child) {

Why not

if ($node->count() == 0 ) { // see http://www.php.net/manual/en/simplexmlelement.count.php
}
else {
  foreach ($node->children() as $child) {
  }
}

What you have looks good but continuing to following a core pattern if possible would be nice.

esbenvb’s picture

Status: Needs work » Needs review

This patch only affects the lines of code INSIDE your for-loop - it handles the case where the array child elements are just a text string. How you handle the for loop outside the code of my patch has nothing to do with that...

marcingy’s picture

Status: Needs review » Needs work

What I am say is don't treat your element as an exception and instead fix the outer loop so as recursion remains in all cases to grab child elements.

esbenvb’s picture

I'll leave the decision up to you, on how to solve this - I know that there are several ways to achieve the same and I just suggested one :)

Anyway, If you want to dramatically change to how Services handles XML, I think it would be best to just treat numeric arrays like a series of elements with the same name.

Like

<article>
<title>Somthing about cute dogs</title>
<tag>Dog</tag>
<tag>Pet</tag>
<tag>Puppy</tag>
<url>http://example.com/something-about-cute-dogs</url>
</article>

Which should be the XML representation of

array(
  'article' => array(
    'title' => 'Somthing about cute dogs',
    'url' => 'http://example.com/something-about-cute-dogs',
    'tag' => array('Dog','Pet','Puppy'),
  ),
);
gielfeldt’s picture

Version: 7.x-3.3 » 7.x-3.5
StatusFileSize
new959 bytes

Here's an updated patch for 7.x-3.5

ygerasimov’s picture

Version: 7.x-3.5 » 7.x-3.x-dev
Status: Needs work » Needs review
kylebrowning’s picture

Status: Needs review » Fixed

FIxed in dev, thanks

Status: Fixed » Closed (fixed)
Issue tags: +

Automatically closed - issue fixed for 2 weeks with no activity.

apanag’s picture

Issue summary: View changes
Status: Closed (fixed) » Needs work

Sorry for reopening the current task, but the patch didn't work me. I tried both XML in comments #1 and #8, apart from my XMLs, but still I was getting a NULL value.
I did my tests with version 3.x-dev. The following code however worked for me:

      if (count($child->children()) > 0) {
        // if the child has children
        $att = 'is_array';
        if ($child->attributes()->$att) {
          $new_array = array();
          // recursive through <item>
          foreach($child->children() as $item) {
            // Make sure that elements with no children gets a value assigned.
            $item_keys = array_keys((array) $item);
            if (count($item_keys) == 1 && current($item_keys) === 0) {
              $new_array[] = (string) $item[0];
            }
            elseif (is_object($item)) {
              $new_array[] = (string) $item;
            }
            else {
              $new_array[] = self::unmarshalXML($item, $array[$item->getName()]);
            }
          }
        }

Let me know, if you need more informations.

apanag’s picture

Status: Needs work » Needs review
StatusFileSize
new1.01 KB

Patch attached with the above code.
Thank you!

kylebrowning’s picture

Status: Needs review » Fixed

Fixed, thanks.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

klokie’s picture

Hi, this recent change has broken compatibility with our incoming XML. Now instead of parsing the content child node <value/>, the array element contains only the whitespace content of the node (e.g. "\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t "). Incoming XML looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<request>
	<type>adresse</type>
	<title>TEST</title>
	<status>1</status>
	<name>foo</name>
	<field_bar>
		<und is_array="true">
			<item>
				<value><![CDATA[rue d'enghien]]></value>
				<format/>
				<safe_value><![CDATA[rue d'enghien]]></safe_value>
			</item>
		</und>
	</field_bar>
</request>

We've been using this format for a while now. Is this still the correct format for XML requests? Thanks.

klokie’s picture

Status: Closed (fixed) » Needs work
bcweaver’s picture

commit f5f16455805b5d16a268b1139d81376e91ba1946
Author: Kyle Browning <kylebrowning@me.com>
Date:   Thu Oct 31 00:01:03 2013 -0700

    Issue #1912842: REST Server XML parser returns arrays with empty values  when POSTing or PUTting... by gielfeldt, esbenvb

This commit included in 7.x-3.6 is breaking my site.. where my resource's update callback had been getting a nice array of entity objects, now it receives an array of empty/whitespace-only values.

Reverting this block in servers/rest_server/includes/ServicesParser.inc starting on line 67:

foreach($child->children() as $item) {
  // Make sure that elements with no children gets a value assigned.
  $item_keys = array_keys((array) $item);
  if (count($item_keys) == 1 && current($item_keys) === 0) {
    $new_array[] = (string) $item[0];
  }
  elseif (is_object($item)) {
    $new_array[] = (string) $item;
  }
  else {
    $new_array[] = self::unmarshalXML($item, $array[$item->getName()]);
  }
}

back to:

 foreach($child->children() as $item) {
   $new_array[] = self::unmarshalXML($item, $array[$item->getName()]);
 }

solves my problem.

kylebrowning’s picture

Looks like our test coverage of XML is abysmal.

I don't have any xml cases setup, any chance I can get some help to resolve this issue?

Im happy to review patches, if nobody can help, ill move towards getting something setup next week.

In the meantime, I would suggest reverting that commit for yourself and placing using that instead of a release.

git revert f5f16455805b5d16a268b1139d81376e91ba1946

akroplas’s picture

Simple patch:
replace
elseif (is_object($item)) {
in
foreach($child->children() as $item)
with
elseif (is_object($item) && ($item->count() == 0)) {

It checks whether $item has children (for example <value>).

Also I've add $array[$child->getName()] = array(); to avoid PHP Notice: Undefined index

akroplas’s picture

Status: Needs work » Needs review
kylebrowning’s picture

kylebrowning’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.