Skip to content

Commit

Permalink
Use target's parent as anchors to (not) delete duplicated ids
Browse files Browse the repository at this point in the history
  • Loading branch information
André L F S Bacci committed Dec 2, 2024
1 parent 2fec2ba commit 0b15c3c
Showing 1 changed file with 66 additions and 47 deletions.
113 changes: 66 additions & 47 deletions configure.php
Original file line number Diff line number Diff line change
Expand Up @@ -790,21 +790,33 @@ function getFileModificationHistory(): array {
$fatal = $ac['LANG'] == 'en';
$xpath = new DOMXPath( $dom );

// pre xinclude() run id capture
// xinclude by xml:id pre run

$listIdPath = [];
$nodes = $xpath->query( "//*[xiparent]" );
if ( $nodes->length > 0 )
{
echo "XML contains elements with 'xiparent' attribute. XInclude by xml:id will fail.\n";
exit(-1);
}

$nodes = $xpath->query( "//*[@xml:id]" );
foreach( $nodes as $node )
$stx = chr( 1 ); // invalid attribute chars
$etx = chr( 2 ); // cannot be used in text

$nodes = $xpath->query( "//*[@xpointer]" );
foreach( $nodes as $xinclude )
{
$id = $node->getAttribute( "xml:id" );
$path = $node->getNodePath();
if ( isset( $listIdPath[ $id ] ) )
{
echo "failed.\nDuplicated xml:id '$id' before XInclude!\n";
errors_are_bad( 1 );
}
$listIdPath[ $id ] = $path;
$id = $xinclude->getAttribute( "xpointer" );
$target = $dom->getElementById( $id );
if ( $target == null )
continue;
$parent = $target->parentNode;
if ( $parent->nodeType != XML_ELEMENT_NODE )
continue;
// creates an 'xiparent' attribute on parent of xi:include xpointer target,
// so these targered elements are not to be changed on later fixup.
$mark = $parent->getAttribute( "xiparent" );
$mark .= "{$stx}{$id}{$etx}";
$parent->setAttribute( "xiparent" , $mark );
}

// automatic xi:fallback
Expand All @@ -816,16 +828,13 @@ function getFileModificationHistory(): array {
$failback = null;

$elements = $node->getElementsByTagName( "fallback" );
if ( count( $elements ) > 0 )
{
$failback = $elements[0];
}
else
if ( count( $elements ) == 0 )
{
$failback = $node->ownerDocument->createElementNS( "http://www.w3.org/2001/XInclude" , "fallback" );
//$failback = $node->ownerDocument->createElement( "xi:fallback" );
$node->append( $failback );
}
else
$failback = $elements[0];

$comment = $failback->ownerDocument->createComment( "xi:fallback $target" );
$failback->append( $comment );
Expand All @@ -842,54 +851,40 @@ function getFileModificationHistory(): array {
libxml_clear_errors();

$status = $ret === -1 ? "failed" : "done";
$countOk = $ret === -1 ? 0 : (int) $ret;
$countErr = count( $errors );
echo "$status. Performed $countOk XIncludes, $countErr failures.\n";
$intret = $ret === -1 ? 0 : (int) $ret;
echo "$status. Performed $intret XIncludes.\n";

// failures

if ( $report )
{
// xi:include failures

foreach( $errors as $error )
fprintf( $print , "\n" . rtrim( $error->message ) . "\n");

if ( $fatal && count( $errors ) )
errors_are_bad( 1 );
fprintf( $print , " Failed xi:include at line: %s\n" , $error->line );

// xi:failback failures

$count = 0;
$nodes = $xpath->query( "//comment()" );

foreach( $nodes as $node )
{
$payload = $node->data;
if ( str_starts_with( $payload , "xi:fallback" ) )
if ( str_starts_with( $payload , "xi:fallback " ) )
{
$count++;
$path = getNodePathWithIds( $node->parentNode );
fprintf( $print , "\nFailed xi:include location: $path\n");

$payload = trim( substr( $payload , 12 ) );
fprintf( $print , "Failed xi:include target is: $payload\n");
fprintf( $print , " Used xi:fallback for target: $payload\n" );
}
}

if ( $count > 0 )
if ( count( $errors ) > 0 )
{
fprintf( $print , "\n");
fprintf( $print , "\n\n");
if ( $fatal )
errors_are_bad( 1 );
}
}

// post run id fixup
// xinclude by xml:id post run fixup

$nodes = $xpath->query( "//*[@xml:id]" );
$count = []; // id : count

$count = [];
foreach( $nodes as $node )
{
$id = $node->getAttribute( "xml:id" );
Expand All @@ -898,19 +893,43 @@ function getFileModificationHistory(): array {

foreach( $nodes as $node )
{
$id = $node->getAttribute( "xml:id" );
$path = $node->getNodePath();
$parent = $node->parentNode;
if ( $parent->nodeType != XML_ELEMENT_NODE )
continue;

// Delete ids with unknown (newer?) paths,
// but do not overdelete if all paths changed.
$id = $node->getAttribute( "xml:id" );
$mark = "$stx" . $id . $etx;
$list = $parent->getAttribute( "xiparent" );
if ( str_contains( $list , $mark ) )
{
if ( $count[ $id ] > 1 )
{
$node->removeAttribute( "xml:id" );
$count[ $id ]--;
}
else
echo "\tStrange, xml:id was to be over deleted: $id\n";
}
}

if ( $listIdPath[ $id ] != $path && $count[ $id ] > 1 )
$list = array();
$nodes = $xpath->query( "//*[@xml:id]" );
foreach( $nodes as $node )
{
$id = $node->getAttribute( "xml:id" );
if ( in_array( $id , $list ) )
{
// may happen while migratating xpointers from xpaths to xml:ids
echo " Random removing duplicated xml:id: $id\n";
$node->removeAttribute( "xml:id" );
$count[ $id ]--;
}
$list[] = $id;
}

$nodes = $xpath->query( "//*[@xiparent]" );
foreach( $nodes as $node )
$node->removeAttribute( "xiparent" );

flush();
}

Expand Down

0 comments on commit 0b15c3c

Please sign in to comment.