Data-Edit-Xml-Xref
view release on metacpan or search on metacpan
lib/Data/Edit/Xml/Xref.pm view on Meta::CPAN
else
{lll "No source for $sourceFile\n";
}
undef # Failed
};
my $checkImageRef = sub # Check whether an image exists or not
{my $i = absFromAbsPlusRel($sourceFile, $ref); # Local file name
return 1 if -e $i; # Local file exists
return 2 if -e wwwDecode($i); # Local file exists
undef # Local file exists after decoding % signs
};
my $fixOnePartialDitaRef = sub # Fix a partial dita reference to an externally cut out topic renamed to the GB Standard where such a reference is just a file name as used in a bookmapref.
{my ($ref) = @_; # Partial reference
return undef unless $xref->fixDitaRefs; # Fixing dita references not requested
my $topicSource = &$locateUniqueTopicSourceForTargetFile($sourceFile); # Unique source file corresponding to the target file else undef
return undef unless $topicSource; # The references can not be resolved without a unique source file.
my $refIn = absFromAbsPlusRel($topicSource, $ref); # The referenced input file that was present in the input being transformed because we assume that (most of) the input Dita refs were valid
if (my $new = $xref->inputFileToTargetTopics->{$refIn}) # The target files new files that were cut out of the referenced input file - there might several such
{if (my $referencedTarget = fileLargestSize(sort keys %$new)) # Boldly assume that the largest possible target is the one we want
{my $link = relFromAbsAgainstAbs($referencedTarget, $sourceFile); # Create relative link from book map
$node->set($attr=>$link);# if $xref->fixBadRefs; # Reset reference - we know fixDitaRefs is true.
&$good($link, q(unique target)); # Record successful fix
return 1; # Success
}
}
undef # Failed
};
my $fixOneFullDitaRef = sub # Fix a full dita reference to an externally cut out topic renamed to the GB Standard where such a reference is: file#topicId/label
{return undef unless $xref->fixDitaRefs; # Fixing dita references not requested
return &$fixOnePartialDitaRef($ref) unless $ref =~ m(#); # Confirm it is a full reference else fix it as a partial reference
my $topicSource = &$locateUniqueTopicSourceForTargetFile($sourceFile); # Unique source file corresponding to the target file else undef
return undef unless $topicSource; # The references can not be resolved without a unique source file.
my ($rf, $rt, $ri) = parseDitaRef($ref, $topicSource); # Parse the dita ref
if (my $new = $xref->originalSourceFileAndIdToNewFile->{$rf}{$ri}) # The new files cut out of the original topic source file
{my $targetFile = relFromAbsAgainstAbs($new, $sourceFile); # Create relative link from current file
if (my $topicId = $xref->topicIds->{$new}) # Topic id for target file
{my $href = qq($targetFile#$topicId/$ri); # New href
$node->set($attr=>$href);# if $xref->fixBadRefs; # Reset href - we know fixDitaRefs is true.
&$good($new, q(Unique target for file ref)); # Record the fix made
return 1; # Record the fix made
}
}
if ($xref->allowUniquePartialMatches && $attr !~ m(\Aconref)s) # Partial matching - i.e ignoring the stuff to the right of the # in the reference sometimes produces a unique result.
{return &$fixOnePartialDitaRef($ref =~ s(#.*\Z) ()rs); # Try to resolve reference as a partial re
}
undef # Failed
};
my $fixRelRef = sub # Attempt to fix a reference broken by relocation
{my ($R, $rest) = split m(#)s, $ref, 2; # Get referenced file name
if ($R)
{my $r = fne($R); # Href file base name
if (my $F = $xref->baseFiles->{$r}) # Relocated else where
{my @targets = sort keys(%$F); # Relocation targets
if (@targets == 1) # Just one such relocation
{my $f = relFromAbsAgainstAbs($targets[0], $sourceFile); # Link to it
if ($f ne $R)
{my $newLink; # Fix if the target is else where
if ($rest) # Link has more than one component
{$node->set($attr=>($newLink = $f.q(#).$rest)); # Reset link
}
else # Link has just one component
{$node->set($attr=>($newLink = $f)); # Reset link
}
my $saveRef = $ref; $ref = $newLink; # Try fixing the relocated reference as a dita reference.
my $r = &$fixOneFullDitaRef;
$ref = $saveRef;
return $r;
}
}
}
}
undef # Failed
};
my $fixOneRef = sub # Fix one unresolved reference either by ameliorating it or by moving it to the xtrf attribute thereby putting it in M3.
{return unless $xref->fixRefs->{$sourceFile}{$ref}; # Fix not requested for this reference
if ($xref->deguidize and $ref =~ m(GUID-)is) # On a guid and deguidization allowed so given g1#g2/id convert g1 to a file name by locating the topic with topicId g2.
{my @refs = split /\s+/, $ref; # There might be multiple references in the href
my @unresolved; # Unresolved targets
my @resolved; # Resolved targets
for my $subRef(@refs) # Each reference in the reference
{my ($guid, $rest) = split /#/, $subRef;
if (my $target = $xref->guidToFile->{$guid}) # Target file associated with guid
{my $link = relFromAbsAgainstAbs($target, $sourceFile); # Relative link
$link .= q(#).$rest if $rest; # Remainder of reference which does not change as it is not file related
if (!@resolved) # First resolution
{$node->set($attr=>$link); # New href or conref
&$good($target, q(Deguidized reference)); # Report fix made
}
push @resolved, $subRef;
}
else
{push @unresolved, $subRef;
}
}
if (@unresolved and $xref->fixBadRefs) # Unresolved - transfer all references to xtrf so some-one else can try
{$node->renameAttr($attr, q(xtrf)); # No target file for guid
&$bad(q(No file for guid)); # Report failure
}
}
elsif ($xref->fixRelocatedRefs and &$fixRelRef) # Try to fix as a relocated ref if possible
{
}
elsif ($xref->fixXrefsByTitle and &$fixXrefByTitle) # Try to fix a missing xref by title
{
}
lib/Data/Edit/Xml/Xref.pm view on Meta::CPAN
Ref_Id The id of the statement in the referenced topic
Source_TopicId The topic id of the referencing file
Target_TopicId The topic id of the referenced file
Source_File The referencing source file
Target_File The referenced target file
END
title => qq(Bad references at start),
facet => $facet, aspectColor=>q(red),
head => <<END,
Xref found NNNN bad references on DDDD at the start of processing
Depending on the options chosen, Xref might fix or ameliorate these references
so that the actual number of references with problems is lower than this. The
best way to find out how many references still need fixing after doing an Xref
run with fixing options enabled is to do another run with all of these options
disabled. The braver elements will be asking why we do not account for these
improvements in flight - that would significantly increase code complexity
while taking a lot of effort to validate yet produce no significant
improvements - so it is much easier not to when a second run suffices.
END
csv => 1, wide =>1, summarize=>1,
file => fpe(q(bad), q(references), q(txt)));
formatTables($xref, \@good, # Report good references
columns => <<END,
Href A good href attribute
Source_File The referencing source file
END
title => qq(Good references at start),
facet => $facet, aspectColor=>q(green),
head => <<END,
Xref found NNNN good references on DDDD at the start of processing.
END
csv => 1, wide =>1, summarize=>1,
file => fpe(q(good), q(references), q(txt)));
# {} # From multiverse to universe 2019.08.29 - no need - we are in series
} # checkReferences
sub reportGuidHrefs($) #P Report on guid hrefs
{my ($xref) = @_; # Cross referencer
my %guidToFile; # Map guids to files
if (my $xrefTopicIds = $xref->topicIds)
{for my $file(sort keys %{$xrefTopicIds}) # Each input file containing a topic id
{my $id = $xrefTopicIds->{$file}; # Each href in the file which will start with guid
next unless defined $id;
next unless $id =~ m(\bguid-)is; # Check guid appears somewhere in href
$guidToFile{$id} = $file; # We report duplicates in reportDuplicateTopicIds
}
}
my @bad; my @good; # Good and bad guid hrefs
for my $file(sort keys %{$xref->guidHrefs}) # Each input file which will be absolute
{my $sourceTopicId = $xref->topicIds->{$file};
for my $href(sort keys %{$xref->guidHrefs->{$file}}) # Each href in the file which will start with guid
{my ($tag, $lineLocation) = @{$xref->guidHrefs->{$file}{$href}}; # Tag of node and location in source file of node doing the referencing
# 2019.08.29 The following line does not appear to be needed - it is happening to late to affect anything
$xref->fixRefs->{$file}{$href}++ unless $xref->fixRefs->{$file}{$href}; # Avoid double counting - all guid hrefs will be fixed if we are fixing hrefs as both good and bad will fail.
if ($href =~ m(#)) # Href with #
{my ($guid, $topic, $id) = split m(#|\/), $href, 3; # Guid, topic, remainder
my $targetFile = $guidToFile{$guid}; # Locate file defining guid
if (!defined $targetFile) # No definition of this guid
{push @bad, # Report missing guid
["No such guid defined", $tag, $href, $lineLocation, q(),
$sourceTopicId, $targetFile, $file];
next;
}
my $targetFileId = $xref->topicIds->{$targetFile} // ''; # Actual id in target file
my $bad = sub
{push @bad,
[@_, $tag, $href, $lineLocation, $targetFileId, $sourceTopicId,
$targetFile, $file];
};
my $good = sub
{push @good,
[$href, $tag, $lineLocation, $targetFile, $file];
};
if (!-e $targetFile) # Existence of file
{$bad->(q(No such file));
}
elsif (defined $topic) # Topic defined so it must be an xref
{if ($topic ne $guid)
{$bad->(q(Guid does not match topic id));
}
elsif (defined $id)
{if (my $i = $xref->ids->{$targetFile}{$id}) # Check id exists in target file
{if ($i == 1)
{&$good;
}
else
{$bad->(q(Duplicate id in topic));
}
}
$bad->(q(No such id in topic));
}
else
{&$good;
}
}
else
{&$good;
}
}
elsif ($tag eq q(image)) # Image reference
{my $guid = $href =~ s(guid|-) ()igsr;
if (my $image = $xref->inputFolderImages->{$guid})
{push @good, [$tag, $href, $lineLocation, $image, $file];
}
else
{push @bad, [qq(No such image guid defined), $tag, $href,
$lineLocation, q(), $sourceTopicId, q(), $file];
}
}
else # No # in href and not an image so it must be a bookmap element
{my $targetFile = $guidToFile{$href};
lib/Data/Edit/Xml/Xref.pm view on Meta::CPAN
if (1) # Report bookmap othermeta after topic othermeta has been included
{my @b;
for my $b(sort keys %b)
{for my $n(sort keys $b{$b}->%*)
{for my $c(sort keys $b{$b}{$n}->%*)
{push @b, [$b, $n, scalar(keys $b{$b}{$n}->%*), $c];
}
}
}
formatTables($xref, $xref->otherMetaBookMapsAfterTopicIncludes = [@b],
columns => <<END,
Bookmap Bookmap file name
Name Bookmap or topic othermeta name
Count Number of distinct values for this othermeta name
Content Othermeta content for this name
END
title=> q(Bookmap othermeta data after topic othermeta has been included),
clearUpLeft => -1, summarize=>1,
head => qq(Xref found NNNN Bookmap othermeta tags after topic othermeta was included on DDDD),
file =>fpe(qw(other_meta book_maps_after_topics_included txt)));
}
{otherMetaDuplicatesSeparately => $xref->otherMetaDuplicatesSeparately,
otherMetaDuplicatesCombined => $xref->otherMetaDuplicatesCombined,
otherMetaRemainWithTopic => $xref->otherMetaRemainWithTopic,
otherMetaPushToBookMap => $xref->otherMetaPushToBookMap,
otherMetaBookMapsBeforeTopicIncludes => $xref->otherMetaBookMapsBeforeTopicIncludes,
otherMetaBookMapsAfterTopicIncludes => $xref->otherMetaBookMapsAfterTopicIncludes,
}
} # reportOtherMeta
sub createSubjectSchemeMap($) #P Create a subject scheme map from othermeta
{my ($xref) = @_; # Cross referencer
my %o; # Consolidated other meta
for my $f(sort keys $xref->otherMeta->%*) # Each file containing othermeta
{for my $n(sort keys $xref->otherMeta->{$f}->%*) # Name of othermeta
{for my $c(sort keys $xref->otherMeta->{$f}->{$n}->%*) # Content of other meta
{$o{$n}{$c}++;
}
}
}
if (my $out = $xref->subjectSchemeMap) # SubjectSchemeMap requested by supplying an output folder for the maps
{my $makeNavTitle = sub # Create a nav title using the Gearhart NavTitle Method
{my ($c) = @_; # Othermeta content
ucfirst $c =~ s(_) ( )gsr # The Gearhart NavTitle method
};
my @m;
for my $n(sort keys %o) # Layout map entries
{next if $n =~ m(\Atopic_type\Z)i;
my $t = &$makeNavTitle($n);
push @m, qq(<subjectHead id="$n" navtitle="$t">);
my %c; # Normalize all the othermeta
for my $content(sort keys $o{$n}->%*)
{for my $c(split m(\s+)s, $content)
{$c{$c}++
}
}
for my $c(sort keys %c) # Write the normalized othermeta
{my $t = &$makeNavTitle($c);
push @m, qq(<subjectdef keys="$c" navtitle="$t"/>);
}
push @m, qq(</subjectHead>);
}
my $m = join "\n", q(<subjectScheme>), @m, q(</subjectScheme>); # Map
my $x = Data::Edit::Xml::new($m); # Parse map
owf($out, $x->ditaPrettyPrintWithHeaders); # Print map
}
{otherMetaConsolidated=>\%o} # Consolidated meta data
} # createSubjectSchemeMap
sub writeClassificationHtml($$) #P Write classification tree as html
{my ($xref, $classification) = @_; # Cross referencer, {title=>{subject=>{file=>++}}}
push my @h, <<END; # Outer table
<style>
.sizeLargeBold
{font-size: 1.2em;
font-weight: bold;
}
</style>
<table id="selectBySubject" border="1" cellpadding="10">
<tr><th>Select by Subject<th>Topics that have been selected
END
push @h, <<END; # Table in column 1 of titles
<tr><td><table border="1" cellpadding="10">
<tr><th>Topic Subject<th>Subject Ref
END
my $iTitle = 0; my $iSubject = 0; # Id generator's for titles and subjects
my @json; # Json holding titles and subjects
for my $t(sort keys %$classification) # Each title
{++$iTitle;
push @h, <<END; # Hidden table of subjects
<tr>
<td valign="top"><a id="clickOnTitle_$iTitle"
onclick="clickOnTitle($iTitle)">$t</a>
<td><div style="display: none" id="title_$iTitle">
<table border="0" cellpadding="10">
END
for my $s(sort keys $classification->{$t}->%*) # Each subject
{++$iSubject;
for my $f(sort keys $classification->{$t}{$s}->%*) # Load topics for title and subject
{push @json, qq(topicDetails.push([$iTitle, $iSubject, "$f"]););
}
push @h, <<END; # Click on subject
<tr><td><span id="clickOnSubject_$iSubject"
onclick='clickOnSubject($iTitle, $iSubject)'>$s</span>
END
}
push @h, <<END; # End hidden table of subjects
</table></div>
END
( run in 0.531 second using v1.01-cache-2.11-cpan-71847e10f99 )