@@ -775,46 +775,108 @@ function getFileModificationHistory(): array {
775775echo "done. \n" ;
776776
777777echo "Running XInclude/XPointer... " ;
778- $ total = 0 ;
779- $ maxrun = 10 ; //LIBXML_VERSION >= 21100 ? 1 : 10;
780- for ( $ run = 0 ; $ run < $ maxrun ; $ run ++ )
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+ echo "$ run " ;
797+ $ xpath = new DOMXPath ( $ dom );
798+ $ xpath ->registerNamespace ( "xi " , "http://www.w3.org/2001/XInclude " );
799+ $ xincludes = $ xpath ->query ( "//xi:include " );
800+
801+ $ progress = false ;
802+ foreach ( $ xincludes as $ xinclude )
803+ {
804+ $ xpointer = $ xinclude ->getAttribute ( "xpointer " );
805+ $ target = $ xinclude ->ownerDocument ->getElementById ( $ xpointer );
806+
807+ if ( $ target == null )
808+ continue ;
809+
810+ $ other = new DOMDocument ( '1.0 ' , 'utf8 ' );
811+ $ frags = $ other ->createDocumentFragment ();
812+ $ other ->append ( $ frags );
813+ $ frags ->append ( $ other ->importNode ( $ target , true ) ); // dup add
814+
815+ // "attributes in xml: namespace are not copied"
816+
817+ $ oxpth = new DOMXPath ( $ other );
818+ $ attribs = $ oxpth ->query ( "//@* " );
819+
820+ foreach ( $ attribs as $ attrib )
821+ if ( $ attrib ->prefix == "xml " )
822+ $ attrib ->parentNode ->removeAttribute ( $ attrib ->nodeName );
823+
824+ $ insert = $ dom ->importNode ( $ frags , true ); // dup
825+ $ xinclude ->parentNode ->insertBefore ( $ insert , $ xinclude ); // add
826+ $ xinclude ->parentNode ->removeChild ( $ xinclude ); // del
827+
828+ $ progress = true ;
829+ $ total ++;
830+ }
831+
832+ if ( $ progress )
833+ continue ;
834+ else
835+ return $ total ;
793836 }
837+ echo "XInclude nested too deeply (xml:id). \n" ;
838+ errors_are_bad ( -1 );
794839}
795840
796- if ($ total == 0 ) {
797- echo "failed. \n" ;
798- } else {
799- echo "done. Performed $ total XIncludes. \n" ;
841+ function xinclude_run_xpointer ( DOMDocument $ dom ) : int
842+ {
843+ $ total = 0 ;
844+ $ maxrun = 10 ; //LIBXML_VERSION >= 21100 ? 1 : 10;
845+ for ( $ run = 0 ; $ run < $ maxrun ; $ run ++ )
846+ {
847+ echo "$ run " ;
848+ libxml_clear_errors ();
849+ $ status = (int ) $ dom ->xinclude ();
850+ if ( $ status <= 0 )
851+ return $ total ;
852+ $ total += $ status ;
853+ }
854+ echo "XInclude nested too deeply (xpointer). \n" ;
855+ errors_are_bad ( -1 );
800856}
801- flush ();
802857
803- if ( $ ac [ ' XPOINTER_REPORTING ' ] == ' yes ' || $ ac [ ' LANG ' ] == ' en ' )
858+ function xinclude_report ( )
804859{
860+ global $ ac ;
861+
862+ $ report = $ ac ['XPOINTER_REPORTING ' ] == 'yes ' || $ ac ['LANG ' ] == 'en ' ;
863+ $ output = $ ac ['STDERR_TO_STDOUT ' ] == 'yes ' ? STDOUT : STDERR ;
864+ $ fatal = $ ac ['LANG ' ] == 'en ' ;
865+
805866 $ errors = libxml_get_errors ();
806- $ output = ( $ ac ['STDERR_TO_STDOUT ' ] == 'yes ' ) ? STDOUT : STDERR ;
807- if ( count ( $ errors ) > 0 )
867+ libxml_clear_errors ();
868+
869+ if ( count ( $ errors ) > 0 && $ report )
808870 {
809- fprintf ( $ output , "\n" );
871+ fprintf ( $ output , "\n\n " );
810872 foreach ( $ errors as $ error )
811- fprintf ( $ output , "{ $ error ->message }\n" );
812- if ( $ ac [ ' LANG ' ] == ' en ' )
813- errors_are_bad (1 );
873+ fprintf ( $ output , rtrim ( $ error ->message ) . "\n\n" );
874+ if ( $ fatal )
875+ errors_are_bad ( 1 );
814876 }
815877}
816878
817- if ( $ ac [ ' LANG ' ] != ' en ' )
879+ function xinclude_residual ( DOMDocument $ dom )
818880{
819881 // XInclude failures are soft errors on translations, so remove
820882 // residual XInclude tags on translations to keep them building.
@@ -844,7 +906,7 @@ function getFileModificationHistory(): array {
844906// $fixup = "<varlistentry><term>></term><listitem><simpara></simpara></listitem></varlistentry>";
845907// break;
846908 default :
847- echo "Unknown parent element of failed XInclude: $ tagName \n" ;
909+ echo "Unknown parent of failed XInclude: $ tagName \n" ;
848910 $ explain = true ;
849911 continue 2 ;
850912 }
@@ -869,6 +931,23 @@ function getFileModificationHistory(): array {
869931MSG ;
870932 exit (-1 ); // stop here, do not let more messages further confuse the matter
871933 }
934+
935+ // XInclude by xml:id never duplicates xml:id, horever, also using
936+ // XInclude by XPath/XPointer may start causing duplications
937+ // (see docs/structure.md). Crude and ugly fixup ahead, beware!
938+
939+ $ list = array ();
940+ $ nodes = $ xpath ->query ( "//*[@xml:id] " );
941+ foreach ( $ nodes as $ node )
942+ {
943+ $ id = $ node ->getAttribute ( "xml:id " );
944+ if ( isset ( $ list [ $ id ] ) )
945+ {
946+ echo " Random removing duplicated xml:id: $ id \n" ;
947+ $ node ->removeAttribute ( "xml:id " );
948+ }
949+ $ list [ $ id ] = $ id ;
950+ }
872951}
873952
874953echo "Validating {$ ac ["INPUT_FILENAME " ]}... " ;
@@ -973,4 +1052,3 @@ function getFileModificationHistory(): array {
9731052
9741053 errors_are_bad (1 ); // Tell the shell that this script finished with an error.
9751054}
976- ?>
0 commit comments