Skip to content

Commit f4654e0

Browse files
committed
Remove XMLStackOfOpenElements class
1 parent eec389e commit f4654e0

File tree

2 files changed

+99
-150
lines changed

2 files changed

+99
-150
lines changed

components/XML/XMLProcessor.php

Lines changed: 99 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,8 @@ class XMLProcessor {
379379
/**
380380
* Specifies mode of operation of the parser at any given time.
381381
*
382-
* | State | Meaning |
383-
* | ----------------|------------------------------------------------------------------------|
382+
* | State | Meaning |
383+
* | ------------------|----------------------------------------------------------------------|
384384
* | *Ready* | The parser is ready to run. |
385385
* | *Complete* | There is nothing left to parse. |
386386
* | *Incomplete* | The XML ended in the middle of a token; nothing more can be parsed. |
@@ -735,13 +735,14 @@ class XMLProcessor {
735735
protected $parser_context = self::IN_PROLOG_CONTEXT;
736736

737737
/**
738-
* Tracks open elements while scanning XML.
739-
*
740-
* @since WP_VERSION
741-
*
742-
* @var XMLStackOfOpenElements
738+
* Top-level namespaces for the currently parsed document.
743739
*/
744-
private $stack_of_open_elements;
740+
private $document_namespaces;
741+
742+
/**
743+
* Tracks open elements and their namespaces while scanning XML.
744+
*/
745+
private $stack_of_open_elements = [];
745746

746747
public static function create_from_string( $xml, $cursor = null, $known_definite_encoding = 'UTF-8', $document_namespaces = array() ) {
747748
$processor = static::create_for_streaming( $xml, $cursor, $known_definite_encoding, $document_namespaces );
@@ -781,7 +782,7 @@ public static function create_for_streaming( $xml = '', $cursor = null, $known_d
781782
*/
782783
public function get_reentrancy_cursor() {
783784
$stack_of_open_elements = [];
784-
foreach ( $this->stack_of_open_elements->get_items() as $element ) {
785+
foreach ( $this->stack_of_open_elements as $element ) {
785786
$stack_of_open_elements[] = $element->to_array();
786787
}
787788

@@ -792,7 +793,8 @@ public function get_reentrancy_cursor() {
792793
'upstream_bytes_forgotten' => $this->upstream_bytes_forgotten,
793794
'parser_context' => $this->parser_context,
794795
'stack_of_open_elements' => $stack_of_open_elements,
795-
'expecting_more_input' => $this->expecting_more_input
796+
'expecting_more_input' => $this->expecting_more_input,
797+
'document_namespaces' => $this->document_namespaces
796798
)
797799
)
798800
);
@@ -837,10 +839,11 @@ protected function initialize_from_cursor( $cursor ) {
837839
// Assume the input stream will start from the last known byte offset.
838840
$this->bytes_already_parsed = 0;
839841
$this->upstream_bytes_forgotten = $cursor['upstream_bytes_forgotten'];
840-
$this->stack_of_open_elements = new XMLStackOfOpenElements();
842+
$this->stack_of_open_elements = [];
841843
foreach ( $cursor['stack_of_open_elements'] as $element ) {
842-
$this->stack_of_open_elements->push( XMLElement::from_array( $element ) );
844+
array_push( $this->stack_of_open_elements, XMLElement::from_array( $element ) );
843845
}
846+
$this->document_namespaces = $cursor['document_namespaces'];
844847
$this->parser_context = $cursor['parser_context'];
845848
$this->expecting_more_input = $cursor['expecting_more_input'];
846849

@@ -876,7 +879,15 @@ protected function __construct( $xml, $document_namespaces=[], $use_the_static_c
876879
);
877880
}
878881
$this->xml = $xml;
879-
$this->stack_of_open_elements = new XMLStackOfOpenElements($document_namespaces);
882+
$this->document_namespaces = array_merge(
883+
$document_namespaces,
884+
// These initial namespaces cannot be overridden.
885+
array(
886+
'xml' => 'http://www.w3.org/XML/1998/namespace', // Predefined, cannot be unbound or changed
887+
'xmlns' => 'http://www.w3.org/2000/xmlns/', // Reserved for xmlns attributes, not a real namespace for elements/attributes
888+
'' => '', // Default namespace is initially empty (no namespace)
889+
)
890+
);
880891
}
881892

882893
/**
@@ -1082,7 +1093,7 @@ protected function parse_next_token() {
10821093
/**
10831094
* By default, inherit all namespaces from the parent element.
10841095
*/
1085-
$namespaces = $this->stack_of_open_elements->get_namespaces_in_scope();
1096+
$namespaces = $this->get_namespaces_in_scope();
10861097
foreach ( $this->qualified_attributes as $attribute ) {
10871098
/**
10881099
* xmlns attribute is the default namespace
@@ -1251,6 +1262,69 @@ protected function parse_next_token() {
12511262
return true;
12521263
}
12531264

1265+
private function get_namespaces_in_scope() {
1266+
$top = $this->top_element();
1267+
if ( null === $top ) {
1268+
// Namespaces defined by default in every XML document.
1269+
return $this->document_namespaces;
1270+
}
1271+
return $top->namespaces_in_scope;
1272+
}
1273+
1274+
/**
1275+
* Returns the namespace prefix of the matched tag or, when the $namespace
1276+
* argument is given, the prefix of the requested fully-qualified namespace .
1277+
*
1278+
* Examples:
1279+
*
1280+
* $p = new XMLProcessor( '<wp:content xmlns:xhtml="http://www.w3.org/1999/xhtml">Test</wp:content>' );
1281+
* $p->next_tag() === true;
1282+
* $p->get_namespace_prefix() === 'xhtml';
1283+
*
1284+
* $p = new XMLProcessor( '
1285+
* <wp:content
1286+
* xmlns:xhtml="http://www.w3.org/1999/xhtml"
1287+
* xmlns:wp="http://wordpress.org/export/1.2/"
1288+
* >
1289+
* Test
1290+
* </wp:content>
1291+
* ' );
1292+
* $p->next_tag() === true;
1293+
* $p->get_namespace_prefix('http://wordpress.org/export/1.2/') === 'wp';
1294+
*
1295+
* @internal
1296+
* @param string|null $namespace Fully-qualified namespace to return the prefix for.
1297+
* @return string|null The namespace prefix of the matched tag, or null if not available.
1298+
*/
1299+
private function get_namespace_prefix($namespace=null) {
1300+
if ( null === $namespace ) {
1301+
if ( self::STATE_MATCHED_TAG !== $this->parser_state ) {
1302+
return null;
1303+
}
1304+
return $this->element->namespace_prefix;
1305+
} else {
1306+
$namespaces_in_scope = $this->get_namespaces_in_scope();
1307+
foreach($namespaces_in_scope as $prefix => $uri) {
1308+
if($uri === $namespace) {
1309+
return $prefix;
1310+
}
1311+
}
1312+
return false;
1313+
}
1314+
}
1315+
1316+
/**
1317+
* Returns the top XMLElement on the stack without removing it.
1318+
*
1319+
* @return XMLElement|null Returns the top element, or null if stack is empty.
1320+
*/
1321+
private function top_element() {
1322+
if ( empty( $this->stack_of_open_elements ) ) {
1323+
return null;
1324+
}
1325+
return $this->stack_of_open_elements[ count( $this->stack_of_open_elements ) - 1 ];
1326+
}
1327+
12541328
/**
12551329
* Whether the processor paused because the input XML document ended
12561330
* in the middle of a syntax element, such as in the middle of a tag.
@@ -2996,25 +3070,6 @@ public function get_tag_name_with_namespace() {
29963070
return '{' . $namespace . '}' . $this->get_tag_local_name();
29973071
}
29983072

2999-
/**
3000-
* Returns the namespace prefix of the matched tag.
3001-
*
3002-
* Example:
3003-
*
3004-
* $p = new XMLProcessor( '<content xmlns:wp="http://www.w3.org/1999/xhtml">Test</content>' );
3005-
* $p->next_tag() === true;
3006-
* $p->get_namespace_prefix() === 'wp';
3007-
*
3008-
* @return string|null The namespace prefix of the matched tag, or null if not available.
3009-
*/
3010-
public function get_namespace_prefix() {
3011-
if ( self::STATE_MATCHED_TAG !== $this->parser_state ) {
3012-
return null;
3013-
}
3014-
3015-
return $this->element->namespace_prefix;
3016-
}
3017-
30183073
/**
30193074
* Returns the namespace reference of the matched tag.
30203075
*
@@ -3035,10 +3090,6 @@ public function get_namespace() {
30353090
return $this->element->namespace;
30363091
}
30373092

3038-
public function get_namespaces_in_scope() {
3039-
return $this->stack_of_open_elements->get_namespaces_in_scope();
3040-
}
3041-
30423093
/**
30433094
* Returns the name from the DOCTYPE declaration.
30443095
*
@@ -3433,7 +3484,7 @@ public function set_attribute( $namespace, $local_name, $value ) {
34333484
$value = htmlspecialchars( $value, ENT_XML1, 'UTF-8' );
34343485

34353486
if($namespace !== '') {
3436-
$prefix = $this->stack_of_open_elements->get_namespace_prefix($namespace);
3487+
$prefix = $this->get_namespace_prefix($namespace);
34373488
if(false === $prefix) {
34383489
$this->bail(
34393490
__( 'The namespace "%1$s" is not in the current element\'s scope.' ),
@@ -3680,9 +3731,10 @@ private function step( $node_to_process = self::PROCESS_NEXT_NODE ) {
36803731

36813732
if ( self::PROCESS_NEXT_NODE === $node_to_process ) {
36823733
if ( $this->is_empty_element() ) {
3683-
$this->stack_of_open_elements->pop();
3734+
array_pop( $this->stack_of_open_elements );
36843735
}
36853736
}
3737+
36863738

36873739
try {
36883740
switch ( $this->parser_context ) {
@@ -3798,15 +3850,15 @@ private function step_in_element( $node_to_process = self::PROCESS_NEXT_NODE ) {
37983850
// Update the stack of open elements
37993851
$tag_qname = $this->get_tag_name_qualified();
38003852
if ( $this->is_tag_closer() ) {
3801-
if(!$this->stack_of_open_elements->count()) {
3853+
if(!count($this->stack_of_open_elements)) {
38023854
$this->bail(
38033855
__( 'The closing tag "%1$s" did not match the opening tag "%2$s".' ),
38043856
$tag_qname,
38053857
$tag_qname
38063858
);
38073859
return false;
38083860
}
3809-
$this->element = $this->stack_of_open_elements->pop();
3861+
$this->element = array_pop( $this->stack_of_open_elements );
38103862
$popped_qname = $this->element->qualified_name;
38113863
if ( $popped_qname !== $tag_qname ) {
38123864
$this->bail(
@@ -3819,12 +3871,12 @@ private function step_in_element( $node_to_process = self::PROCESS_NEXT_NODE ) {
38193871
self::ERROR_SYNTAX
38203872
);
38213873
}
3822-
if ( $this->stack_of_open_elements->count() === 0 ) {
3874+
if ( count( $this->stack_of_open_elements ) === 0 ) {
38233875
$this->parser_context = self::IN_MISC_CONTEXT;
38243876
}
38253877
} else {
3826-
$this->stack_of_open_elements->push( $this->element );
3827-
$this->element = $this->stack_of_open_elements->top();
3878+
array_push( $this->stack_of_open_elements, $this->element );
3879+
$this->element = $this->top_element();
38283880
}
38293881

38303882
return true;
@@ -3908,7 +3960,7 @@ private function step_in_misc( $node_to_process = self::PROCESS_NEXT_NODE ) {
39083960
public function get_breadcrumbs() {
39093961
return array_map( function( $element ) {
39103962
return array( $element->namespace, $element->local_name );
3911-
}, $this->stack_of_open_elements->get_items() );
3963+
}, $this->stack_of_open_elements );
39123964
}
39133965

39143966
/**
@@ -3950,7 +4002,7 @@ public function matches_breadcrumbs( $breadcrumbs ) {
39504002
return false;
39514003
}
39524004

3953-
$open_elements = $this->stack_of_open_elements->get_items();
4005+
$open_elements = $this->stack_of_open_elements;
39544006
$crumb_count = count( $breadcrumbs );
39554007
$elem_count = count( $open_elements );
39564008

@@ -4011,7 +4063,7 @@ public function matches_breadcrumbs( $breadcrumbs ) {
40114063
*
40124064
*/
40134065
public function get_current_depth() {
4014-
return $this->stack_of_open_elements->count();
4066+
return count( $this->stack_of_open_elements );
40154067
}
40164068

40174069
/**

components/XML/XMLStackOfOpenElements.php

Lines changed: 0 additions & 103 deletions
This file was deleted.

0 commit comments

Comments
 (0)