Skip to content

Commit 45f488c

Browse files
alfsbkamil-tekiela
andauthoredMar 13, 2025··
Workarounds for DOMDocument->xinclude() return (#237)
* Workarounds for DOMDocument->xinclude() return * Review. Co-authored-by: Kamil Tekiela <tekiela246@gmail.com>
1 parent f91fb15 commit 45f488c

File tree

1 file changed

+85
-75
lines changed

1 file changed

+85
-75
lines changed
 

‎configure.php

+85-75
Original file line numberDiff line numberDiff line change
@@ -872,8 +872,7 @@ function dom_saveload( DOMDocument $dom , string $filename = "" ) : string
872872
else
873873
echo "done. Performed $total XIncludes.\n";
874874

875-
xinclude_report();
876-
xinclude_residual( $dom );
875+
xinclude_residual_fixup( $dom );
877876

878877
function xinclude_run_byid( DOMDocument $dom )
879878
{
@@ -927,94 +926,46 @@ function xinclude_run_byid( DOMDocument $dom )
927926

928927
function xinclude_run_xpointer( DOMDocument $dom ) : int
929928
{
929+
// The return of xinclude() cannot be used for counting or stoping, as it
930+
// sometimes return zero/negative in cases of partial executions
931+
930932
$total = 0;
931-
$maxrun = 10; //LIBXML_VERSION >= 21100 ? 1 : 10;
932-
for( $run = 0 ; $run < $maxrun ; $run++ )
933+
for( $run = 0 ; $run < 10 ; $run++ )
933934
{
934935
echo "$run ";
935-
$status = (int) $dom->xinclude();
936+
libxml_clear_errors();
936937

937-
if ( $status <= 0 )
938-
{
938+
$was = count( xinclude_residual_list( $dom ) );
939+
$dom->xinclude();
940+
$now = count( xinclude_residual_list( $dom ) );
941+
942+
$total += $was - $now;
943+
944+
if ( $was === $now )
939945
return $total;
940-
}
941-
$total += $status;
942-
libxml_clear_errors();
943946
}
944947
echo "XInclude nested too deeply (xpointer).\n";
945948
errors_are_bad( 1 );
946949
}
947950

948-
function xinclude_report()
951+
function xinclude_residual_fixup( DOMDocument $dom )
949952
{
950-
global $ac;
951-
952-
$report = $ac['XPOINTER_REPORTING'] == 'yes' || $ac['LANG'] == 'en';
953-
$output = $ac['STDERR_TO_STDOUT'] == 'yes' ? STDOUT : STDERR;
954-
$fatal = $ac['LANG'] == 'en';
955-
956-
$errors = libxml_get_errors();
957-
libxml_clear_errors();
958-
959-
if ( ! $report )
960-
return;
961-
962-
$count = 0;
963-
$prefix = realpath( __DIR__ );
964-
965-
$prevLine = -1;
966-
$prevClmn = -1;
967-
968-
foreach( $errors as $error )
969-
{
970-
$msg = $error->message;
971-
$file = $error->file;
972-
$line = $error->line;
973-
$clmn = $error->column;
974-
975-
if ( $prevLine == $line && $prevClmn == $clmn )
976-
continue; // XPointer failures double reports sometimes
977-
$prevLine = $line;
978-
$prevClmn = $clmn;
979-
980-
$msg = rtrim( $msg );
981-
if ( str_starts_with( $file , $prefix ) )
982-
$file = substr( $file , strlen( $prefix ) + 1 );
983-
984-
if ( $count == 0 )
985-
fprintf( $output , "\n" );
986-
987-
fprintf( $output , "[{$file} {$line}:{$clmn}] $msg\n" );
988-
$count++;
989-
}
953+
xinclude_debug_report( $dom );
990954

991-
if ( $count > 0 )
992-
{
993-
fprintf( $output , "\n" );
994-
if ( $fatal )
995-
errors_are_bad( 1 );
996-
}
997-
}
998-
999-
function xinclude_residual( DOMDocument $dom )
1000-
{
1001955
// XInclude failures are soft errors on translations, so remove
1002956
// residual XInclude tags on translations to keep them building.
1003957

1004-
$header = false;
958+
$nodes = xinclude_residual_list( $dom );
959+
960+
$count = 0;
1005961
$explain = false;
1006962

1007-
$xpath = new DOMXPath( $dom );
1008-
$xpath->registerNamespace( "xi" , "http://www.w3.org/2001/XInclude" );
1009-
$nodes = $xpath->query( "//xi:include" );
1010963
foreach( $nodes as $node )
1011964
{
1012-
if ( $header == false )
1013-
{
965+
if ( $count === 0 )
1014966
echo "\nFailed XInclude:\n";
1015-
$header = true;
1016-
}
1017-
echo "- {$node->getAttribute("xpointer")}\n";
967+
echo " {$node->getAttribute("xpointer")}\n";
968+
$count++;
1018969

1019970
$fixup = null;
1020971
$parent = $node->parentNode;
@@ -1051,9 +1002,6 @@ function xinclude_residual( DOMDocument $dom )
10511002
$node->parentNode->removeChild( $node );
10521003
}
10531004

1054-
if ( $header )
1055-
echo "\n";
1056-
10571005
if ( $explain )
10581006
{
10591007
echo <<<MSG
@@ -1063,15 +1011,19 @@ function xinclude_residual( DOMDocument $dom )
10631011
state. Please report any "Unknown parent" messages on the doc-base
10641012
repository, and focus on fixing XInclude/XPointers failures above.\n\n
10651013
MSG;
1066-
exit(1); // stop here, do not let more messages further confuse the matter
1014+
exit( 1 ); // stop here, do not let more messages further confuse the matter
10671015
}
10681016

1017+
if ( $count > 0 )
1018+
echo "\n";
1019+
10691020
// XInclude by xml:id never duplicates xml:id, horever, also using
10701021
// XInclude by XPath/XPointer may start causing duplications
10711022
// (see docs/structure.md). Crude and ugly fixup ahead, beware!
10721023

1024+
$list = [];
10731025
$see = false;
1074-
$list = array();
1026+
$xpath = new DOMXPath( $dom );
10751027
$nodes = $xpath->query( "//*[@xml:id]" );
10761028
foreach( $nodes as $node )
10771029
{
@@ -1089,6 +1041,64 @@ function xinclude_residual( DOMDocument $dom )
10891041
}
10901042
if ( $see )
10911043
echo " See: https://github.com/php/doc-base/blob/master/docs/structure.md#xmlid-structure\n";
1044+
1045+
$fatal = $GLOBALS['ac']['LANG'] == 'en';
1046+
1047+
if ( $see && $fatal )
1048+
errors_are_bad( 1 ); // Duplicated strucutral xml:ids are fatal on doc-en
1049+
}
1050+
1051+
function xinclude_residual_list( DOMDocument $dom ) : DOMNodeList
1052+
{
1053+
$xpath = new DOMXPath( $dom );
1054+
$xpath->registerNamespace( "xi" , "http://www.w3.org/2001/XInclude" );
1055+
$nodes = $xpath->query( "//xi:include" );
1056+
1057+
return $nodes;
1058+
}
1059+
1060+
function xinclude_debug_report( DOMDocument $dom )
1061+
{
1062+
$debugFile = __DIR__ . "/temp/xinclude-debug.xml";
1063+
1064+
dom_saveload( $dom , $debugFile ); // preserve state
1065+
1066+
libxml_clear_errors();
1067+
$dom->xinclude();
1068+
$errors = libxml_get_errors();
1069+
libxml_clear_errors();
1070+
1071+
dom_saveload( $dom ); // normal output
1072+
1073+
$count = 0;
1074+
$prefix = realpath( __DIR__ );
1075+
1076+
$prevLine = -1;
1077+
$prevClmn = -1;
1078+
1079+
foreach( $errors as $error )
1080+
{
1081+
$msg = $error->message;
1082+
$file = $error->file;
1083+
$line = $error->line;
1084+
$clmn = $error->column;
1085+
1086+
$prevLine = $line;
1087+
$prevClmn = $clmn;
1088+
1089+
$msg = rtrim( $msg );
1090+
if ( str_starts_with( $file , $prefix ) )
1091+
$file = substr( $file , strlen( $prefix ) + 1 );
1092+
1093+
if ( $count === 0 )
1094+
echo "\n";
1095+
1096+
echo "[{$file} {$line}:{$clmn}] $msg\n";
1097+
$count++;
1098+
}
1099+
1100+
if ( $count === 0 )
1101+
echo "\n";
10921102
}
10931103

10941104
echo "Validating {$ac["INPUT_FILENAME"]}... ";

0 commit comments

Comments
 (0)
Please sign in to comment.