Skip to content

Commit 43aa6f7

Browse files
committed
[XMLProcessor] Support custom processing instructions
1 parent a1495c8 commit 43aa6f7

File tree

3 files changed

+27
-24
lines changed

3 files changed

+27
-24
lines changed

components/XML/Tests/W3CXMLConformanceTest.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,6 @@ public function test_w3c_xml_test_case($test_id, $test_type, $test_file, $descri
5858
return;
5959
}
6060

61-
if (in_array($test_id, [
62-
"not-sa04",
63-
"sa04",
64-
"ibm-valid-P01-ibm01v01.xml",
65-
])) {
66-
$this->markTestSkipped("Skipping test case: {$test_id} – XMLProcessor does not support custom processing directive targets (e.g. <?music ... ?>)");
67-
return;
68-
}
69-
7061
if (in_array($test_id, [
7162
"ibm-1-1-valid-P02-ibm02v01.xml",
7263
"ibm-1-1-valid-P02-ibm02v02.xml",

components/XML/Tests/XMLProcessorTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,19 @@ public function test_processor_instructions() {
15011501
'The modifiable text was not correctly captured.' );
15021502
}
15031503

1504+
public function test_custom_processing_instruction_target() {
1505+
$processor = XMLProcessor::create_from_string( '<?music "notes"?><post/>' );
1506+
$this->assertTrue( $processor->next_token(), 'The custom processing instruction was not found.' );
1507+
$this->assertEquals(
1508+
'#processing-instructions',
1509+
$processor->get_token_type(),
1510+
'The custom processing instruction was not correctly identified.'
1511+
);
1512+
$this->assertSame( ' "notes"', $processor->get_modifiable_text() );
1513+
$this->assertTrue( $processor->next_token(), 'The element following the processing instruction was not found.' );
1514+
$this->assertSame( 'post', $processor->get_token_name(), 'The element following the processing instruction was not parsed correctly.' );
1515+
}
1516+
15041517
/**
15051518
* Ensures that updates which are enqueued in front of the cursor
15061519
* are applied before moving forward in the document.

components/XML/class-xmlprocessor.php

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,27 +2106,26 @@ private function parse_next_tag() {
21062106
* `<?` denotes a processing instruction.
21072107
* See https://www.w3.org/TR/xml/#sec-pi
21082108
*/
2109-
if (
2110-
! $this->is_closing_tag &&
2111-
'?' === $xml[ $at + 1 ]
2112-
) {
2113-
if ( $at + 4 >= $doc_length ) {
2109+
if ( ! $this->is_closing_tag && '?' === $xml[ $at + 1 ] ) {
2110+
if ( $at + 2 >= $doc_length ) {
21142111
$this->mark_incomplete_input();
21152112

21162113
return false;
21172114
}
21182115

2119-
if ( ! (
2120-
( 'x' === $xml[ $at + 2 ] || 'X' === $xml[ $at + 2 ] ) &&
2121-
( 'm' === $xml[ $at + 3 ] || 'M' === $xml[ $at + 3 ] ) &&
2122-
( 'l' === $xml[ $at + 4 ] || 'L' === $xml[ $at + 4 ] )
2123-
) ) {
2116+
$target_length = $this->parse_name( $at + 2 );
2117+
if ( false === $target_length ) {
2118+
return false;
2119+
}
2120+
2121+
if ( 0 === $target_length ) {
21242122
$this->bail( 'Invalid processing instruction target.', self::ERROR_SYNTAX );
21252123
}
21262124

2127-
$at += 5;
2125+
$target_ends_at = $at + 2 + $target_length;
2126+
$this->bytes_already_parsed = $target_ends_at;
21282127

2129-
// Skip whitespace.
2128+
// Skip whitespace after the target, if any.
21302129
$this->skip_whitespace();
21312130

21322131
/*
@@ -2141,16 +2140,16 @@ private function parse_next_tag() {
21412140
* closing ?> is found. Some failures may pass unnoticed. That may not be a problem in practice,
21422141
* but if it is then this code path will require a stricter implementation.
21432142
*/
2144-
$closer_at = strpos( $xml, '?>', $at );
2143+
$closer_at = strpos( $xml, '?>', $this->bytes_already_parsed );
21452144
if ( false === $closer_at ) {
21462145
$this->mark_incomplete_input();
21472146

21482147
return false;
21492148
}
21502149

21512150
$this->parser_state = self::STATE_PI_NODE;
2152-
$this->token_length = $closer_at + 5 - $this->token_starts_at;
2153-
$this->text_starts_at = $this->token_starts_at + 5;
2151+
$this->token_length = $closer_at + 2 - $this->token_starts_at;
2152+
$this->text_starts_at = $target_ends_at;
21542153
$this->text_length = $closer_at - $this->text_starts_at;
21552154
$this->bytes_already_parsed = $closer_at + 2;
21562155

0 commit comments

Comments
 (0)