Skip to content

Commit

Permalink
Applying patch from 'Stefano Rosanelli' which fixes Xml::toArray() gr…
Browse files Browse the repository at this point in the history
…eatly improving

its ability to convert xml documents.  Fixes #1667
  • Loading branch information
markstory committed Apr 22, 2011
1 parent f0b7066 commit 5105d5c
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 32 deletions.
49 changes: 18 additions & 31 deletions cake/libs/xml.php
Expand Up @@ -660,11 +660,11 @@ function toString($options = array(), $depth = 0) {
*/
function toArray($camelize = true) {
$out = $this->attributes;
$multi = null;

foreach ($this->children as $child) {
$key = $camelize ? Inflector::camelize($child->name) : $child->name;

$leaf = false;
if (is_a($child, 'XmlTextNode')) {
$out['value'] = $child->value;
continue;
Expand All @@ -673,47 +673,34 @@ function toArray($camelize = true) {
if ($child->attributes) {
$value = array_merge(array('value' => $value), $child->attributes);
}
if (isset($out[$child->name]) || isset($multi[$key])) {
if (!isset($multi[$key])) {
$multi[$key] = array($out[$child->name]);
unset($out[$child->name]);
}
$multi[$key][] = $value;
} else {
$out[$child->name] = $value;
if (count($child->children) == 1) {
$leaf = true;
}
continue;
} elseif (count($child->children) === 0 && $child->value == '') {
$value = $child->attributes;
if (isset($out[$key]) || isset($multi[$key])) {
if (!isset($multi[$key])) {
$multi[$key] = array($out[$key]);
//unset($out[$key]);
}
$multi[$key][] = $value;
} elseif (!empty($value)) {
$out[$key] = $value;
} else {
$out[$child->name] = $value;
if (empty($value)) {
$leaf = true;
}
continue;
} else {
$value = $child->toArray($camelize);
}

if (!isset($out[$key])) {
$out[$key] = $value;
} else {
if (!is_array($out[$key]) || !isset($out[$key][0])) {
if (isset($out[$key])) {
if(!isset($out[$key][0]) || !is_array($out[$key]) || !is_int(key($out[$key]))) {
$out[$key] = array($out[$key]);
}
}
$out[$key][] = $value;
} elseif (isset($out[$child->name])) {
$t = $out[$child->name];
unset($out[$child->name]);
$out[$key] = array($t);
$out[$key][] = $value;
} elseif ($leaf) {
$out[$child->name] = $value;
} else {
$out[$key] = $value;
}
}

if (isset($multi)) {
$out = array_merge($out, $multi);
}
return $out;
}
/**
Expand Down Expand Up @@ -1400,4 +1387,4 @@ function &getInstance() {
return $instance[0];
}
}
?>
?>
192 changes: 191 additions & 1 deletion cake/tests/cases/libs/xml.test.php
Expand Up @@ -1390,5 +1390,195 @@ function testMemoryLeakInConstructor() {
$end = memory_get_usage();
$this->assertWithinMargin($start, $end, 3600, 'Memory leaked %s');
}

/**
* Test toArray with alternate inputs.
*
* @return void
*/
function testToArrayAlternate() {
$sXml =
'<t1>
<t2>A</t2>
<t2><t3>AAA</t3>B</t2>
<t2>C</t2>
</t1>';
$xml = new Xml($sXml);
$result = $xml->toArray();
$expected = array(
'T1' => array(
'T2' => array(
'A',
array('t3' => 'AAA', 'value' => 'B'),
'C'
)
)
);
$this->assertIdentical($result, $expected);
$result = $xml->toArray(false);
$expected = array(
't1' => array(
't2' => array(
'A',
array('t3' => 'AAA', 'value' => 'B'),
'C'
)
)
);
$this->assertIdentical($result, $expected);

$sXml =
'<t1>
<t2>A</t2>
<t2>B</t2>
<t2>
<t3>CCC</t3>
</t2>
</t1>';
$xml = new Xml($sXml);
$result = $xml->toArray();
$expected = array(
'T1' => array(
'T2' => array(
'A',
'B',
array('t3' => 'CCC'),
)
)
);
$this->assertIdentical($result, $expected);
$result = $xml->toArray(false);
$expected = array(
't1' => array(
't2' => array(
'A',
'B',
array('t3' => 'CCC'),
)
)
);
$this->assertIdentical($result, $expected);

$sXml =
'<t1>
<t2>A</t2>
<t2></t2>
<t2>C</t2>
</t1>';
$xml = new Xml($sXml);
$result = $xml->toArray();
$expected = array(
'T1' => array(
'T2' => array(
'A',
array(),
'C'
)
)
);
$this->assertIdentical($result, $expected);

$result = $xml->toArray(false);
$expected = array(
't1' => array(
't2' => array(
'A',
array(),
'C'
)
)
);
$this->assertIdentical($result, $expected);

$sXml =
'<stuff>
<foo name="abc-16" profile-id="Default" />
<foo name="abc-17" profile-id="Default" >
<bar id="HelloWorld" />
</foo>
<foo name="abc-asdf" profile-id="Default" />
<foo name="cba-1A" profile-id="Default">
<bar id="Baz" />
</foo>
<foo name="cba-2A" profile-id="Default">
<bar id="Baz" />
</foo>
<foo name="qa" profile-id="Default" />
</stuff>';
$xml = new Xml($sXml);
$result = $xml->toArray();
$expected = array(
'Stuff' => array(
'Foo' => array(
array('name' => 'abc-16', 'profile-id' => 'Default'),
array('name' => 'abc-17', 'profile-id' => 'Default',
'Bar' => array('id' => 'HelloWorld')),
array('name' => 'abc-asdf', 'profile-id' => 'Default'),
array('name' => 'cba-1A', 'profile-id' => 'Default',
'Bar' => array('id' => 'Baz')),
array('name' => 'cba-2A', 'profile-id' => 'Default',
'Bar' => array('id' => 'Baz')),
array('name' => 'qa', 'profile-id' => 'Default'),
)
)
);
$this->assertIdentical($result, $expected);
$result = $xml->toArray(false);
$expected = array(
'stuff' => array(
'foo' => array(
array('name' => 'abc-16', 'profile-id' => 'Default'),
array('name' => 'abc-17', 'profile-id' => 'Default',
'bar' => array('id' => 'HelloWorld')),
array('name' => 'abc-asdf', 'profile-id' => 'Default'),
array('name' => 'cba-1A', 'profile-id' => 'Default',
'bar' => array('id' => 'Baz')),
array('name' => 'cba-2A', 'profile-id' => 'Default',
'bar' => array('id' => 'Baz')),
array('name' => 'qa', 'profile-id' => 'Default'),
)
)
);
$this->assertIdentical($result, $expected);


$sXml =
'<root>
<node name="first" />
<node name="second"><subnode name="first sub" /><subnode name="second sub" /></node>
<node name="third" />
</root>';
$xml = new Xml($sXml);
$result = $xml->toArray();
$expected = array(
'Root' => array(
'Node' => array(
array('name' => 'first'),
array('name' => 'second',
'Subnode' => array(
array('name' => 'first sub'),
array('name' => 'second sub'))),
array('name' => 'third'),
)
)
);
$this->assertIdentical($result, $expected);

$result = $xml->toArray(false);
$expected = array(
'root' => array(
'node' => array(
array('name' => 'first'),
array('name' => 'second',
'subnode' => array(
array('name' => 'first sub'),
array('name' => 'second sub'))),
array('name' => 'third'),
)
)
);
$this->assertIdentical($result, $expected);
}

}
?>
?>

0 comments on commit 5105d5c

Please sign in to comment.