LaTeXML
view release on metacpan or search on metacpan
lib/LaTeXML/Post.pm view on Meta::CPAN
$node->removeChild($child); $n++; } }
return $n; }
# Replace $node by @replacements in the document
sub replaceNode {
my ($self, $node, @replacements) = @_;
my ($parent, $following) = ($node->parentNode, undef);
# Note that since we can only append new stuff, we've got to remove the following first.
my @save = ();
while (($following = $parent->lastChild) && ($$following != $$node)) { # Remove & Save following siblings.
unshift(@save, $parent->removeChild($following)); }
$self->removeNodes($node);
$self->addNodes($parent, @replacements);
map { $parent->appendChild($_) } @save; # Put these back.
return; }
# Put @nodes at the beginning of $node.
sub prependNodes {
my ($self, $node, @nodes) = @_;
my @save = ();
# Note that since we can only append new stuff, we've got to remove the following first.
while (my $last = $node->lastChild) { # Remove, but save, all children
unshift(@save, $node->removeChild($last)); }
$self->addNodes($node, @nodes); # Now, add the new nodes.
map { $node->appendChild($_) } @save; # Put these back.
return; }
# Clone a node, but adjusting it so that it has unique id's.
# $document->cloneNode($node) or ->cloneNode($node,$idsuffix)
# This clones the node and adjusts any xml:id's within it to be unique.
# Any idref's to those ids will be changed to the new id values.
# If $idsuffix is supplied, it can be a simple string to append to the ids;
# else can be a function of the id to modify it.
# Then each $id is checked to see whether it is unique; If needed,
# one or more letters are appended, until a new id is found.
sub cloneNode {
my ($self, $node, $idsuffix, %options) = @_;
return $node unless ref $node;
return $node if ref $node eq 'ARRAY'; # Should we deep clone if we get an array? Just return for now
my $copy = $node->cloneNode(1);
my $nocache = $options{nocache};
#### $idsuffix = '' unless defined $idsuffix;
# Find all id's defined in the copy and change the id.
my %idmap = ();
foreach my $n ($self->findnodes('descendant-or-self::*[@xml:id]', $copy)) {
my $id = $n->getAttribute('xml:id');
my $newid = $self->uniquifyID($id, $idsuffix);
$idmap{$id} = $newid;
$self->recordID($newid => $n) unless $nocache;
$n->setAttribute('xml:id' => $newid);
if (my $fragid = $n->getAttribute('fragid')) { # GACK!!
$n->setAttribute(fragid => substr($newid, length($id) - length($fragid))); } }
# Now, replace all REFERENCES to those modified ids.
foreach my $n ($self->findnodes('descendant-or-self::*[@idref]', $copy)) {
if (my $id = $idmap{ $n->getAttribute('idref') }) {
$n->setAttribute(idref => $id); } } # use id or fragid?
# Finally, we probably shouldn't have any labels attributes in here either
foreach my $n ($self->findnodes('descendant-or-self::*[@labels]', $copy)) {
$n->removeAttribute('labels'); }
# And, if we're relocating the node across documents,
# we may need to patch relative pathnames!
# ????? Something to think about in the future...
# if(my $base = $options{basepathname}){
# foreach my $n ($self->findnodes('descendant::*/@graphic or descendant::*/@href', $copy)) {
# $n->setvalue(relocate($n->value,$base)); }}
return $copy; }
sub cloneNodes {
my ($self, @nodes) = @_;
return map { $self->cloneNode($_) } @nodes; }
sub addSSValues {
my ($self, $node, $key, $values) = @_;
$values = $values->toAttribute if ref $values;
if ((defined $values) && ($values ne '')) { # Skip if `empty'; but 0 is OK!
my @values = split(/\s/, $values);
if (my $oldvalues = $node->getAttribute($key)) { # previous values?
my @old = split(/\s/, $oldvalues);
foreach my $new (@values) {
push(@old, $new) unless grep { $_ eq $new } @old; }
$node->setAttribute($key => join(' ', sort @old)); }
else {
$node->setAttribute($key => join(' ', sort @values)); } }
return; }
sub addClass {
my ($self, $node, $class) = @_;
return $self->addSSValues($node, class => $class); }
#======================================================================
# DUPLICATED from Core::Document...(see discussion there)
# Decorations on one side of an XMDual should be attributed to the
# parent node on the other side (see ->associateIDs)
sub markXMNodeVisibility {
my ($self) = @_;
foreach my $math ($self->findnodes('//ltx:XMath/*')) {
$self->markXMNodeVisibility_aux($math, 1, 1); }
return; }
sub markXMNodeVisibility_aux {
no warnings 'recursion';
my ($self, $node, $cvis, $pvis) = @_;
return unless $node;
my $qname = $self->getQName($node);
return if (!$cvis || $node->getAttribute('_cvis')) && (!$pvis || $node->getAttribute('_pvis'));
$node->setAttribute('_cvis' => 1) if $cvis;
$node->setAttribute('_pvis' => 1) if $pvis;
if ($qname eq 'ltx:XMDual') {
my ($c, $p) = element_nodes($node);
$self->markXMNodeVisibility_aux($c, 1, 0) if $cvis;
$self->markXMNodeVisibility_aux($p, 0, 1) if $pvis; }
elsif ($qname eq 'ltx:XMRef') {
# $self->markXMNodeVisibility_aux($self->realizeXMNode($node),$cvis,$pvis); }
my $id = $node->getAttribute('idref');
$self->markXMNodeVisibility_aux($self->findNodeByID($id), $cvis, $pvis); }
else {
foreach my $child (element_nodes($node)) {
$self->markXMNodeVisibility_aux($child, $cvis, $pvis); } }
return; }
#======================================================================
# Given a list of nodes (or node constructors [tag,attr,content...])
# conjoin given a conjunction like ',' or a pair like [',', ' and ']
sub conjoin {
( run in 0.332 second using v1.01-cache-2.11-cpan-71847e10f99 )