@@ -774,47 +774,108 @@ function getFileModificationHistory(): array {
774774}
775775echo "done. \n" ;
776776
777- echo "Running XInclude/XPointer... " ;
778- $ total = 0 ;
779- $ maxrun = 10 ; //LIBXML_VERSION >= 21100 ? 1 : 10;
780- for ( $ run = 0 ; $ run < $ maxrun ; $ run ++ )
777+ echo "Running XInclude... " ;
778+
779+ $ total = xinclude_run_byid ( $ dom );
780+ $ total += xinclude_run_xpointer ( $ dom );
781+
782+ if ( $ total == 0 )
783+ echo "failed. \n" ;
784+ else
785+ echo "done. Performed $ total XIncludes. \n" ;
786+
787+ xinclude_report ();
788+ xinclude_residual ( $ dom );
789+
790+ function xinclude_run_byid ( DOMDocument $ dom )
781791{
782- if ( $ run > 0 )
783- echo "$ run " ;
784- libxml_clear_errors ();
785- $ status = (int ) $ dom ->xinclude ();
786- if ( $ status <= 0 )
787- break ;
788- $ total += $ status ;
789- if ( $ maxrun > 1 && $ run + 1 >= $ maxrun )
792+ $ total = 0 ;
793+ $ maxrun = 10 ; //LIBXML_VERSION >= 21100 ? 1 : 10;
794+ for ( $ run = 0 ; $ run < $ maxrun ; $ run ++ )
790795 {
791- echo "Recursive XInclude is too deep. \n" ;
792- errors_are_bad (-1 );
796+ $ xpath = new DOMXPath ( $ dom );
797+ $ xpath ->registerNamespace ( "xi " , "http://www.w3.org/2001/XInclude " );
798+ $ xincludes = $ xpath ->query ( "//xi:include " );
799+
800+ $ progress = false ;
801+ foreach ( $ xincludes as $ xinclude )
802+ {
803+ $ xpointer = $ xinclude ->getAttribute ( "xpointer " );
804+ $ target = $ xinclude ->ownerDocument ->getElementById ( $ xpointer );
805+
806+ if ( $ target == null )
807+ continue ;
808+
809+ $ other = new DOMDocument ( '1.0 ' , 'utf8 ' );
810+ $ frags = $ other ->createDocumentFragment ();
811+ $ other ->append ( $ frags );
812+ $ frags ->append ( $ other ->importNode ( $ target , true ) ); // dup add
813+
814+ // "attributes in xml: namespace are not copied"
815+
816+ $ oxpth = new DOMXPath ( $ other );
817+ $ attribs = $ oxpth ->query ( "//@* " );
818+
819+ foreach ( $ attribs as $ attrib )
820+ if ( $ attrib ->prefix == "xml " )
821+ $ attrib ->parentNode ->removeAttribute ( $ attrib ->nodeName );
822+
823+ $ insert = $ dom ->importNode ( $ frags , true ); // dup
824+ $ xinclude ->parentNode ->insertBefore ( $ insert , $ xinclude ); // add
825+ $ xinclude ->parentNode ->removeChild ( $ xinclude ); // del
826+
827+ $ progress = true ;
828+ $ total ++;
829+ }
830+
831+ if ( $ progress )
832+ continue ;
833+ else
834+ return $ total ;
793835 }
836+ echo "XInclude nested too deeply (xml:id). \n" ;
837+ errors_are_bad ( -1 );
794838}
795839
796- if ($ total == 0 ) {
797- echo "failed. \n" ;
798- } else {
799- echo "done. Performed $ total XIncludes. \n" ;
840+ function xinclude_run_xpointer ( DOMDocument $ dom ) : int
841+ {
842+ $ total = 0 ;
843+ $ maxrun = 10 ; //LIBXML_VERSION >= 21100 ? 1 : 10;
844+ for ( $ run = 0 ; $ run < $ maxrun ; $ run ++ )
845+ {
846+ echo ". " ;
847+ libxml_clear_errors ();
848+ $ status = (int ) $ dom ->xinclude ();
849+ if ( $ status <= 0 )
850+ return $ total ;
851+ $ total += $ status ;
852+ }
853+ echo "XInclude nested too deeply (xpointer). \n" ;
854+ errors_are_bad ( -1 );
800855}
801- flush ();
802856
803- if ( $ ac [ ' XPOINTER_REPORTING ' ] == ' yes ' || $ ac [ ' LANG ' ] == ' en ' )
857+ function xinclude_report ( )
804858{
859+ global $ ac ;
860+
861+ $ report = $ ac ['XPOINTER_REPORTING ' ] == 'yes ' || $ ac ['LANG ' ] == 'en ' ;
862+ $ output = $ ac ['STDERR_TO_STDOUT ' ] == 'yes ' ? STDOUT : STDERR ;
863+ $ fatal = $ ac ['LANG ' ] == 'en ' ;
864+
805865 $ errors = libxml_get_errors ();
806- $ output = ( $ ac ['STDERR_TO_STDOUT ' ] == 'yes ' ) ? STDOUT : STDERR ;
807- if ( count ( $ errors ) > 0 )
866+ libxml_clear_errors ();
867+
868+ if ( count ( $ errors ) > 0 && $ report )
808869 {
809- fprintf ( $ output , "\n" );
870+ fprintf ( $ output , "\n\n " );
810871 foreach ( $ errors as $ error )
811- fprintf ( $ output , "{ $ error ->message }\n" );
812- if ( $ ac [ ' LANG ' ] == ' en ' )
813- errors_are_bad (1 );
872+ fprintf ( $ output , rtrim ( $ error ->message ) . "\n\n" );
873+ if ( $ fatal )
874+ errors_are_bad ( 1 );
814875 }
815876}
816877
817- if ( $ ac [ ' LANG ' ] != ' en ' )
878+ function xinclude_residual ( DOMDocument $ dom )
818879{
819880 // XInclude failures are soft errors on translations, so remove
820881 // residual XInclude tags on translations to keep them building.
@@ -869,6 +930,23 @@ function getFileModificationHistory(): array {
869930MSG ;
870931 exit (-1 ); // stop here, do not let more messages further confuse the matter
871932 }
933+
934+ // XInclude by xml:id never duplicates xml:id, horever, also using
935+ // XInclude by XPath/XPointer may start causing duplications.
936+ // Crude and ugly fixup ahead, beware!
937+
938+ $ list = array ();
939+ $ nodes = $ xpath ->query ( "//*[@xml:id] " );
940+ foreach ( $ nodes as $ node )
941+ {
942+ $ id = $ node ->getAttribute ( "xml:id " );
943+ if ( isset ( $ list [ $ id ] ) )
944+ {
945+ echo " Random removing duplicated xml:id: $ id \n" ;
946+ $ node ->removeAttribute ( "xml:id " );
947+ }
948+ $ list [ $ id ] = $ id ;
949+ }
872950}
873951
874952echo "Validating {$ ac ["INPUT_FILENAME " ]}... " ;
0 commit comments