Skip to content

Commit 627c7d5

Browse files
committed
Fix #11: Use DOM to determine actual namespace of current element
1 parent 16622d9 commit 627c7d5

File tree

5 files changed

+62
-36
lines changed

5 files changed

+62
-36
lines changed

src/simplexml_dump.php

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,26 @@ function simplexml_dump(SimpleXMLElement $sxml, $return=false)
3939
// It's surprisingly hard to find something which behaves consistently differently for an attribute and an element within SimpleXML
4040
// The below relies on the fact that the DOM makes a much clearer distinction
4141
// Note that this is not an expensive conversion, as we are only swapping PHP wrappers around an existing LibXML resource
42-
if ( dom_import_simplexml($item) instanceOf DOMAttr )
42+
$dom_item = dom_import_simplexml($item);
43+
44+
// To what namespace does this element or attribute belong? Returns array( alias => URI )
45+
$ns_prefix = $dom_item->prefix;
46+
$ns_uri = $dom_item->namespaceURI;
47+
48+
if ( $dom_item instanceOf DOMAttr )
4349
{
4450
$dump .= $indent . 'Attribute {' . PHP_EOL;
4551

46-
// To what namespace does this attribute belong? Returns array( alias => URI )
47-
$ns = $item->getNamespaces(false);
48-
if ( $ns )
52+
if ( ! is_null($ns_uri) )
4953
{
50-
$dump .= $indent . $indent . 'Namespace: \'' . reset($ns) . '\'' . PHP_EOL;
51-
if ( key($ns) == '' )
54+
$dump .= $indent . $indent . 'Namespace: \'' . $ns_uri . '\'' . PHP_EOL;
55+
if ( $ns_prefix == '' )
5256
{
5357
$dump .= $indent . $indent . '(Default Namespace)' . PHP_EOL;
5458
}
5559
else
5660
{
57-
$dump .= $indent . $indent . 'Namespace Alias: \'' . key($ns) . '\'' . PHP_EOL;
61+
$dump .= $indent . $indent . 'Namespace Alias: \'' . $ns_prefix . '\'' . PHP_EOL;
5862
}
5963
}
6064

@@ -67,18 +71,16 @@ function simplexml_dump(SimpleXMLElement $sxml, $return=false)
6771
{
6872
$dump .= $indent . 'Element {' . PHP_EOL;
6973

70-
// To what namespace does this element belong? Returns array( alias => URI )
71-
$ns = $item->getNamespaces(false);
72-
if ( $ns )
74+
if ( ! is_null($ns_uri) )
7375
{
74-
$dump .= $indent . $indent . 'Namespace: \'' . reset($ns) . '\'' . PHP_EOL;
75-
if ( key($ns) == '' )
76+
$dump .= $indent . $indent . 'Namespace: \'' . $ns_uri . '\'' . PHP_EOL;
77+
if ( $ns_prefix == '' )
7678
{
7779
$dump .= $indent . $indent . '(Default Namespace)' . PHP_EOL;
7880
}
7981
else
8082
{
81-
$dump .= $indent . $indent . 'Namespace Alias: \'' . key($ns) . '\'' . PHP_EOL;
83+
$dump .= $indent . $indent . 'Namespace Alias: \'' . $ns_prefix . '\'' . PHP_EOL;
8284
}
8385
}
8486

src/simplexml_tree.php

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,30 +37,31 @@ function simplexml_tree(SimpleXMLElement $sxml, $include_string_content=false, $
3737
{
3838
$root_item = $sxml[$root_item_index];
3939

40+
// The DOM exposes information which SimpleXML doesn't make easy to find
41+
// Note that this is not an expensive conversion, as we are only swapping PHP wrappers around an existing LibXML resource
42+
$dom_item = dom_import_simplexml($root_item);
43+
44+
// To what namespace does this element or attribute belong?
45+
$ns_prefix = $dom_item->prefix;
46+
4047
// Special case if the root is actually an attribute
4148
// It's surprisingly hard to find something which behaves consistently differently for an attribute and an element within SimpleXML
42-
// The below relies on the fact that the DOM makes a much clearer distinction
43-
// Note that this is not an expensive conversion, as we are only swapping PHP wrappers around an existing LibXML resource
44-
if ( dom_import_simplexml($root_item) instanceOf DOMAttr )
49+
if ( $dom_item instanceOf DOMAttr )
4550
{
46-
// To what namespace does this attribute belong? Returns array( alias => URI )
47-
$ns = $root_item->getNamespaces(false);
48-
if ( key($ns) )
51+
if ( $ns_prefix )
4952
{
50-
$dump .= key($ns) . ':';
53+
$dump .= $ns_prefix . ':';
5154
}
5255
$dump .= $root_item->getName() . '="' . (string)$root_item . '"' . PHP_EOL;
5356
}
5457
else
5558
{
5659
// Display the root node as a numeric key reference, plus a hint as to its tag name
5760
// e.g. '[42] // <Answer>'
58-
59-
// To what namespace does this attribute belong? Returns array( alias => URI )
60-
$ns = $root_item->getNamespaces(false);
61-
if ( key($ns) )
61+
62+
if ( $ns_prefix )
6263
{
63-
$root_node_name = key($ns) . ':' . $root_item->getName();
64+
$root_node_name = $ns_prefix . ':' . $root_item->getName();
6465
}
6566
else
6667
{
@@ -123,19 +124,22 @@ function _simplexml_tree_recursively_process_node($item, $depth, $include_string
123124
}
124125
}
125126

126-
// To what namespace does this element belong? Returns array( alias => URI )
127+
// The DOM exposes information which SimpleXML doesn't make easy to find
128+
// Note that this is not an expensive conversion, as we are only swapping PHP wrappers around an existing LibXML resource
129+
$dom_item = dom_import_simplexml($item);
130+
131+
// To what namespace does this element or attribute belong?
132+
127133
// For top-level elements, cheat, and say they're in the null namespace, to force a ->children() call
128134
if ( $depth == 1 )
129135
{
130-
$item_ns = array('' => NULL);
136+
$item_ns_prefix = '';
137+
$item_ns_uri = null;
131138
}
132139
else
133140
{
134-
$item_ns = $item->getNamespaces(false);
135-
if ( !$item_ns )
136-
{
137-
$item_ns = array('' => NULL);
138-
}
141+
$item_ns_prefix = $dom_item->prefix;
142+
$item_ns_uri = $dom_item->namespaceURI;
139143
}
140144

141145
// This returns all namespaces used by this node and all its descendants,
@@ -146,18 +150,21 @@ function _simplexml_tree_recursively_process_node($item, $depth, $include_string
146150
{
147151
$all_ns[''] = NULL;
148152
}
149-
153+
150154
// Prioritise "current" namespace by merging into onto the beginning of the list
151155
// (it will be added to the beginning and the duplicate entry dropped)
152-
$all_ns = array_merge($item_ns, $all_ns);
153-
156+
$all_ns = array_merge(
157+
array($item_ns_prefix => $item_ns_uri),
158+
$all_ns
159+
);
160+
154161
foreach ( $all_ns as $ns_alias => $ns_uri )
155162
{
156163
$children = $item->children($ns_alias, true);
157164
$attributes = $item->attributes($ns_alias, true);
158165

159166
// If things are in the current namespace, display them a bit differently
160-
$is_current_namespace = ( $ns_uri == reset($item_ns) );
167+
$is_current_namespace = ( $ns_uri == $item_ns_uri );
161168

162169
$ns_uri_quoted = (strlen($ns_uri) == 0 ? 'null' : "'$ns_uri'");
163170

tests/dump-output/issue-11

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
SimpleXML object (1 item)
2+
[
3+
Element {
4+
Name: 'notinnamespace'
5+
String Content: ''
6+
Content in Namespace test
7+
Namespace URI: 'http://example.com'
8+
Children: 0
9+
Attributes: 1 - 'isinnamespace'
10+
}
11+
]

tests/input/issue-11.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?xml version="1.0" standalone="yes"?>
2+
<notinnamespace xmlns:test="http://example.com" test:isinnamespace="true" />

tests/tree-output/issue-11

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SimpleXML object (1 item)
2+
[0] // <notinnamespace>
3+
->attributes('http://example.com')
4+
->isinnamespace

0 commit comments

Comments
 (0)