[stringtemplate-interest] best way to expose xml in template

Nate misc at n4te.com
Wed Dec 6 17:12:24 PST 2006


Below is my workaround to be able to use a Set as StringTemplate 
attribute and use an expression like "$if(set.key)$". It was either this 
or maintain my own ST distro.

-Nate


/**
* A Map that wraps a Set where the values come from the Set and the keys 
are the result of Object#toString() on the values.
*/
public abstract class SetMap implements Map {
private final Set set;

public SetMap (Set set) {
this.set = set;
}

abstract protected Object keyToValue (Object key);

/**
* Default implementation returns the String representation of the value.
*/
protected Object valueToKey (Object value) {
return value.toString();
}

public void clear () {
set.clear();
}

public boolean containsKey (Object key) {
return containsValue(keyToValue(key));
}

public boolean containsValue (Object value) {
return set.contains(value);
}

/**
* The Map.Entry objects in the returned Set do not support the {@link 
Map.Entry#setValue(Object)} method.
*/
public Set entrySet () {
return new AbstractSet() {
public int size () {
return set.size();
}

public Iterator iterator () {
return new SetMapEntryIterator(set);
}
};
}

public Object get (Object key) {
return keyToValue(key);
}

public boolean isEmpty () {
return set.isEmpty();
}

public Set keySet () {
return new AbstractSet() {
public int size () {
return set.size();
}

public Iterator iterator () {
return new SetMapKeyIterator(set);
}
};
}

public Object put (Object key, Object value) {
return set.add(value) ? null : value;
}

public void putAll (Map map) {
for (Iterator iter = map.values().iterator(); iter.hasNext();)
set.add(iter.next());
}

public Object remove (Object key) {
Object value = keyToValue(key);
if (value != null) set.remove(value);
return value;
}

public int size () {
return set.size();
}

public Collection values () {
return set;
}

private class SetMapEntryIterator implements Iterator {
private final Iterator iter;

public SetMapEntryIterator (Set set) {
this.iter = set.iterator();
}

public boolean hasNext () {
return iter.hasNext();
}

public Object next () {
return new Map.Entry() {
private Object value = iter.next();

public Object setValue (Object value) {
throw new UnsupportedOperationException();
}

public Object getValue () {
return value;
}

public Object getKey () {
return valueToKey(value);
}
};
}

public void remove () {
iter.remove();
}
}

private class SetMapKeyIterator implements Iterator {
private final Iterator iter;

public SetMapKeyIterator (Set set) {
this.iter = set.iterator();
}

public boolean hasNext () {
return iter.hasNext();
}

public Object next () {
return valueToKey(iter.next());
}

public void remove () {
iter.remove();
}
}
}



Nate wrote:
> Terence Parr wrote:
>   
>> On Dec 5, 2006, at 5:24 PM, Nate wrote:
>>     
>>> Thanks for the reply.
>>>
>>> It would be great if there were an interface that could be implemented
>>> that had simply #get(String).
>>>     
>>>       
>>   That is probably too flexible, leading a bigger hole I want.   
>> Allowing the map interface took a lot of convincing from other people  
>> before I did it. ;)
>>   
>>     
> Maybe true, but the hole is there either way.
>
>   
>>> Also Collection could be supported... $if (someSet.moo)$ would be
>>> equivalent to the Java: if (someSet.contains("moo"))
>>>     
>>>       
>> That is too much like logic I think.
>>   
>>     
> While this message has the subject "best way to expose xml in a 
> template", the actual problem I encountered that prompted support for 
> Collection#contains is this... I have a user object with a Set<String> 
> of "capabilities". I would like to check in my templates if the user has 
> a given capability. Eg, the template should show an "admin tools" link 
> if the user has the capability "can view admin tools". I could manually 
> add the capabilities that the template needs to know about as 
> attributes, but if a different set of templates is used to display the 
> page then they may require knowledge of different capabilities. Eg, the 
> "admin tools" link may be in a different template. The easiest solution 
> I think is to add an attribute for every template called "capabilities" 
> that contains the Set, then use...
> $if(capabilities.("can view admin tools"))$<a href=...>admin 
> tools</a>$endif$
>
> -Nate
>   


More information about the stringtemplate-interest mailing list