[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[EP-tech] <epc:list>



So, today I've been refactoring our citation file as it was a mess. I 
split it into one citation per type and made some more citation files 
for the more complex fields.

That worked really well, but there was still an issue that lots of cases 
needed me to render a comma separated list of fields where some of them 
may not be set but you don't want to have "Thing 1, , , Thing 4.". 
Doubled up commas are hard to avoid.

So, I wrote a handy new feature. This works like this:

 ?<epc:list join=", " suffix=".">
 ??? <epc:item><epc:if test="thing_a"><epc:print expr="thing_a" 
/></epc:if></epc:item>
 ??? <epc:item><epc:if test="thing_b"><epc:print expr="thing_b" 
/></epc:if></epc:item>
 ??? <epc:item><epc:if test="thing_c"><epc:print expr="thing_c" 
/></epc:if></epc:item>
 ??? <epc:item><epc:if test="thing_d"><epc:print expr="thing_d" 
/></epc:if></epc:item>
</epc:list>

This will render each list item and only keep it if it contains 
characters other than whitespace and tags. so "<span> </span>" will be 
skipped but "Foo" will be included.

It uses the? join text to join each non-empty list item and if there are 
one or more non-empty items, it puts the suffix and prefix text at the 
start and end. You can also use first-join and last-join to use 
different link text between the first or last pair.

This feature can be added to current EPrints by overriding a subroutine. 
It's brutal, but works. It may require review after a major upgrade. (or 
maybe someone will add the feature to the next release!)

This is new and not very tested code, so at your own risk etc.



{
no warnings 'redefine';
*EPrints::XML::EPC::process = sub {
	my( $node, %params ) = @_;

	if( !defined $node )
	{
		EPrints::abort( "no node passed to epc process" );
	}
# cjg - Potential bug if: <ifset a><ifset b></></> and ifset a is disposed
# then ifset: b is processed it will crash.

	if( EPrints::XML::is_dom( $node, "Element" ) )
	{
		my $name = $node->tagName;
		$name =~ s/^epc://;

		return $params{session}->xml->create_document_fragment
			if $node->hasAttribute( "disabled" ) && $node->getAttribute( "disabled" );

		if( $name=~m/^(if|comment|choose|print|debug|phrase|pin|foreach|set|list)$/ )
		{
			my $fn = "EPrints::XML::EPC::_process_$name";
			no strict "refs";
			my $r = eval { &{$fn}( $node, %params ); };
			use strict "refs";
			if( $@ )
			{
				$params{session}->log( "EPScript error: $@" );
				return $params{session}->html_phrase( "XML/EPC:script_error" );
			}
			return $r;
		}
	}

	my $collapsed = $params{session}->clone_for_me( $node );
	my $attrs = $collapsed->attributes;
	if( defined $attrs )
	{
		for( my $i = 0; $i<$attrs->length; ++$i )
		{
			my $attr = $attrs->item( $i );
			my $v = $attr->nodeValue;
			my $name = $attr->nodeName;
			my $newv = eval { EPrints::XML::EPC::expand_attribute( $v, $name, \%params ); };
			if( $@ )
			{
				$params{session}->log( "EPScript error: $@" );
				$newv = $params{session}->phrase( "XML/EPC:script_error" );
			}
			if( $v ne $newv ) { $attr->setValue( $newv ); }
		}
	}

	if( $node->hasChildNodes )
	{
		$collapsed->appendChild( EPrints::XML::EPC::process_child_nodes( $node, %params ) );
	}
	return $collapsed;
}
} # end of block that disabled 'redefine' warnings


sub EPrints::XML::EPC::_process_list
{
	my( $node, %params ) = @_;

	# if there's only 2 items and first & last join are defined then last join is used.
	my $opts = {};
	foreach my $atr ( qw/ join suffix prefix first-join last-join / )
	{
		if( $node->hasAttribute( $atr ) )
		{
			$opts->{$atr} = $node->getAttribute( $atr );
		}
	}

	my @out_nodes = ();
	foreach my $child ( $node->getChildNodes )
	{
		next unless( EPrints::XML::is_dom( $child, "Element" ) );
		my $name = $child->tagName;
		$name=~s/^ep://;
		$name=~s/^epc://;
		if( ! $name eq "item" )
		{
			EPrints::abort( "In ".$params{in}.": only epc:item is allowed in epc:list.\n".substr( $child->toString, 0, 100 ) );
		}
		
		my $collapsed_item = EPrints::XML::EPC::process_child_nodes( $child, %params );
		
		# Add result to the output list IF it's not just whitespace
		my $text = $params{session}->xml->to_string( $collapsed_item );
		$text =~ s/\s//g;
		if( $text ne "" )
		{
			push @out_nodes, $collapsed_item;
		}
	}

	my $result = $params{session}->make_doc_fragment;
	if( scalar @out_nodes > 0 )
	{
		# at least one item!
		if( defined $opts->{prefix} )
		{
			$result->appendChild( $params{session}->make_text( $opts->{prefix} ) );
		}
		for( my $pos=0; $pos < scalar @out_nodes; ++$pos )
		{
			my $join;
			if( $pos > 0 ) {
				$join = $opts->{join};
				if( $pos == 1 && defined $opts->{"first-join"} ) { $join = $opts->{"first-join"}; }
				if( $pos == ((scalar @out_nodes)-1) && defined $opts->{"last-join"} ) { $join = $opts->{"last-join"}; }
			}
			if( defined $join )
			{
				$result->appendChild( $params{session}->make_text( $join ) );
			}
			$result->appendChild( $out_nodes[$pos] );
		}
		if( defined $opts->{suffix} )
		{
			$result->appendChild( $params{session}->make_text( $opts->{suffix} ) );
		}
	}
				
	return $result;
}



-- 
Christopher Gutteridge -- http://users.ecs.soton.ac.uk/cjg

University of Southampton Open Data Service: http://data.southampton.ac.uk/
You should read our Web & Data Innovation blog: http://blogs.ecs.soton.ac.uk/webteam/