simplenlg.framework.PhraseElement Maven / Gradle / Ivy
/*
* The contents of this file are subject to the Mozilla Public License
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* https://www.mozilla.org/en-US/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is "Simplenlg".
*
* The Initial Developer of the Original Code is Ehud Reiter, Albert Gatt and Dave Westwater.
* Portions created by Ehud Reiter, Albert Gatt and Dave Westwater are Copyright (C) 2010-11 The University of Aberdeen. All Rights Reserved.
*
* Contributor(s): Ehud Reiter, Albert Gatt, Dave Westwater, Roman Kutlak, Margaret Mitchell, and Saad Mahamood.
*/
package simplenlg.framework;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import simplenlg.features.ClauseStatus;
import simplenlg.features.DiscourseFunction;
import simplenlg.features.Feature;
import simplenlg.features.InternalFeature;
import simplenlg.phrasespec.NPPhraseSpec;
/**
*
* This class defines a phrase. It covers the expected phrase types: noun
* phrases, verb phrases, adjective phrases, adverb phrases and prepositional
* phrases as well as also covering clauses. Phrases can be constructed from
* scratch by setting the correct features of the phrase elements. However, it
* is strongly recommended that the PhraseFactory
is used to
* construct phrases.
*
*
* @author D. Westwater, University of Aberdeen.
* @version 4.0
*/
public class PhraseElement extends NLGElement {
/**
* Creates a new phrase of the given type.
*
* @param newCategory the PhraseCategory
type for this phrase.
*/
public PhraseElement(PhraseCategory newCategory) {
setCategory(newCategory);
// set default feature value
setFeature(Feature.ELIDED, false);
}
/**
*
* This method retrieves the child components of this phrase. The list
* returned will depend on the category of the element.
*
* - Clauses consist of cue phrases, front modifiers, pre-modifiers,
* subjects, verb phrases and complements.
* - Noun phrases consist of the specifier, pre-modifiers, the noun
* subjects, complements and post-modifiers.
* - Verb phrases consist of pre-modifiers, the verb group, complements
* and post-modifiers.
* - Canned text phrases have no children thus an empty list will be
* returned.
* - All the other phrases consist of pre-modifiers, the main phrase
* element, complements and post-modifiers.
*
*
*
* @return a List
of NLGElement
s representing the
* child elements of this phrase.
*/
@Override
public List getChildren() {
List children = new ArrayList();
ElementCategory category = getCategory();
NLGElement currentElement = null;
if(category instanceof PhraseCategory) {
switch((PhraseCategory) category){
case CLAUSE:
currentElement = getFeatureAsElement(Feature.CUE_PHRASE);
if(currentElement != null) {
children.add(currentElement);
}
children.addAll(getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS));
children.addAll(getFeatureAsElementList(InternalFeature.PREMODIFIERS));
children.addAll(getFeatureAsElementList(InternalFeature.SUBJECTS));
children.addAll(getFeatureAsElementList(InternalFeature.VERB_PHRASE));
children.addAll(getFeatureAsElementList(InternalFeature.COMPLEMENTS));
break;
case NOUN_PHRASE:
currentElement = getFeatureAsElement(InternalFeature.SPECIFIER);
if(currentElement != null) {
children.add(currentElement);
}
children.addAll(getFeatureAsElementList(InternalFeature.PREMODIFIERS));
currentElement = getHead();
if(currentElement != null) {
children.add(currentElement);
}
children.addAll(getFeatureAsElementList(InternalFeature.COMPLEMENTS));
children.addAll(getFeatureAsElementList(InternalFeature.POSTMODIFIERS));
break;
case VERB_PHRASE:
children.addAll(getFeatureAsElementList(InternalFeature.PREMODIFIERS));
currentElement = getHead();
if(currentElement != null) {
children.add(currentElement);
}
children.addAll(getFeatureAsElementList(InternalFeature.COMPLEMENTS));
children.addAll(getFeatureAsElementList(InternalFeature.POSTMODIFIERS));
break;
case CANNED_TEXT:
// Do nothing
break;
default:
children.addAll(getFeatureAsElementList(InternalFeature.PREMODIFIERS));
currentElement = getHead();
if(currentElement != null) {
children.add(currentElement);
}
children.addAll(getFeatureAsElementList(InternalFeature.COMPLEMENTS));
children.addAll(getFeatureAsElementList(InternalFeature.POSTMODIFIERS));
break;
}
}
return children;
}
/**
* Sets the head, or main component, of this current phrase. For example,
* the head for a verb phrase should be a verb while the head of a noun
* phrase should be a noun. String
s are converted to
* StringElement
s. If null
is passed in as the new
* head then the head feature is removed.
*
* @param newHead the new value for the head of this phrase.
*/
public void setHead(Object newHead) {
if(newHead == null) {
removeFeature(InternalFeature.HEAD);
return;
}
NLGElement headElement;
if(newHead instanceof NLGElement)
headElement = (NLGElement) newHead;
else
headElement = new StringElement(newHead.toString());
setFeature(InternalFeature.HEAD, headElement);
}
/**
* Retrieves the current head of this phrase.
*
* @return the NLGElement
representing the head.
*/
public NLGElement getHead() {
return getFeatureAsElement(InternalFeature.HEAD);
}
/**
*
* Adds a new complement to the phrase element. Complements will be realised
* in the syntax after the head element of the phrase. Complements differ
* from post-modifiers in that complements are crucial to the understanding
* of a phrase whereas post-modifiers are optional.
*
*
*
* If the new complement being added is a clause or a
* CoordinatedPhraseElement
then its clause status feature is
* set to ClauseStatus.SUBORDINATE
and it's discourse function
* is set to DiscourseFunction.OBJECT
by default unless an
* existing discourse function exists on the complement.
*
*
*
* Complements can have different functions. For example, the phrase John
* gave Mary a flower has two complements, one a direct object and one
* indirect. If a complement is not specified for its discourse function,
* then this is automatically set to DiscourseFunction.OBJECT
.
*
*
* @param newComplement the new complement as an NLGElement
.
*/
public void addComplement(NLGElement newComplement) {
List complements = getFeatureAsElementList(InternalFeature.COMPLEMENTS);
if(complements == null) {
complements = new ArrayList();
}
// check if the new complement has a discourse function; if not, assume
// object
if(!newComplement.hasFeature(InternalFeature.DISCOURSE_FUNCTION)) {
newComplement.setFeature(InternalFeature.DISCOURSE_FUNCTION, DiscourseFunction.OBJECT);
}
complements.add(newComplement);
setFeature(InternalFeature.COMPLEMENTS, complements);
if(newComplement.isA(PhraseCategory.CLAUSE) || newComplement instanceof CoordinatedPhraseElement) {
newComplement.setFeature(InternalFeature.CLAUSE_STATUS, ClauseStatus.SUBORDINATE);
if(!newComplement.hasFeature(InternalFeature.DISCOURSE_FUNCTION)) {
newComplement.setFeature(InternalFeature.DISCOURSE_FUNCTION, DiscourseFunction.OBJECT);
}
}
}
/**
*
* Sets a complement of the phrase element. If a complement already exists
* of the same DISCOURSE_FUNCTION, it is removed. This replaces complements
* set earlier via {@link #addComplement(NLGElement)}
*
*
* @param newComplement the new complement as an NLGElement
.
*/
public void setComplement(NLGElement newComplement) {
DiscourseFunction function = (DiscourseFunction) newComplement.getFeature(InternalFeature.DISCOURSE_FUNCTION);
removeComplements(function);
addComplement(newComplement);
}
/**
* remove complements of the specified DiscourseFunction
*/
private void removeComplements(DiscourseFunction function) {
List complements = getFeatureAsElementList(InternalFeature.COMPLEMENTS);
if(function == null || complements == null)
return;
List complementsToRemove = new ArrayList();
for(NLGElement complement : complements)
if(function == complement.getFeature(InternalFeature.DISCOURSE_FUNCTION))
complementsToRemove.add(complement);
if(!complementsToRemove.isEmpty()) {
complements.removeAll(complementsToRemove);
setFeature(InternalFeature.COMPLEMENTS, complements);
}
return;
}
/**
*
* Adds a new complement to the phrase element. Complements will be realised
* in the syntax after the head element of the phrase. Complements differ
* from post-modifiers in that complements are crucial to the understanding
* of a phrase whereas post-modifiers are optional.
*
*
* @param newComplement the new complement as a String
. It is used to
* create a StringElement
.
*/
public void addComplement(String newComplement) {
StringElement newElement = new StringElement(newComplement);
List complements = getFeatureAsElementList(InternalFeature.COMPLEMENTS);
if(complements == null) {
complements = new ArrayList();
}
complements.add(newElement);
setFeature(InternalFeature.COMPLEMENTS, complements);
}
/**
*
* Sets the complement to the phrase element. This replaces any complements
* set earlier.
*
*
* @param newComplement the new complement as a String
. It is used to
* create a StringElement
.
*/
public void setComplement(String newComplement) {
setFeature(InternalFeature.COMPLEMENTS, null);
addComplement(newComplement);
}
/**
* Adds a new post-modifier to the phrase element. Post-modifiers will be
* realised in the syntax after the complements.
*
* @param newPostModifier the new post-modifier as an NLGElement
.
*/
public void addPostModifier(NLGElement newPostModifier) {
List postModifiers = getFeatureAsElementList(InternalFeature.POSTMODIFIERS);
if(postModifiers == null) {
postModifiers = new ArrayList();
}
newPostModifier.setFeature(InternalFeature.DISCOURSE_FUNCTION, DiscourseFunction.POST_MODIFIER);
postModifiers.add(newPostModifier);
setFeature(InternalFeature.POSTMODIFIERS, postModifiers);
}
/**
* Adds a new post-modifier to the phrase element. Post-modifiers will be
* realised in the syntax after the complements.
*
* @param newPostModifier the new post-modifier as a String
. It is used to
* create a StringElement
.
*/
public void addPostModifier(String newPostModifier) {
List postModifiers = getFeatureAsElementList(InternalFeature.POSTMODIFIERS);
if(postModifiers == null) {
postModifiers = new ArrayList();
}
postModifiers.add(new StringElement(newPostModifier));
setFeature(InternalFeature.POSTMODIFIERS, postModifiers);
}
/**
* Set the postmodifier for this phrase. This resets all previous
* postmodifiers to null
and replaces them with the given
* string.
*
* @param newPostModifier the postmodifier
*/
public void setPostModifier(String newPostModifier) {
this.setFeature(InternalFeature.POSTMODIFIERS, null);
addPostModifier(newPostModifier);
}
/**
* Set the postmodifier for this phrase. This resets all previous
* postmodifiers to null
and replaces them with the given
* string.
*
* @param newPostModifier the postmodifier
*/
public void setPostModifier(NLGElement newPostModifier) {
this.setFeature(InternalFeature.POSTMODIFIERS, null);
addPostModifier(newPostModifier);
}
/**
* Adds a new front modifier to the phrase element.
*
* @param newFrontModifier the new front modifier as an NLGElement
.
*/
public void addFrontModifier(NLGElement newFrontModifier) {
List frontModifiers = getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS);
if(frontModifiers == null) {
frontModifiers = new ArrayList();
}
frontModifiers.add(newFrontModifier);
setFeature(InternalFeature.FRONT_MODIFIERS, frontModifiers);
}
/**
* Adds a new front modifier to the phrase element.
*
* @param newFrontModifier the new front modifier as a String
. It is used to
* create a StringElement
.
*/
public void addFrontModifier(String newFrontModifier) {
List frontModifiers = getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS);
if(frontModifiers == null) {
frontModifiers = new ArrayList();
}
frontModifiers.add(new StringElement(newFrontModifier));
setFeature(InternalFeature.FRONT_MODIFIERS, frontModifiers);
}
/**
* Set the frontmodifier for this phrase. This resets all previous front
* modifiers to null
and replaces them with the given string.
*
* @param newFrontModifier the front modifier
*/
public void setFrontModifier(String newFrontModifier) {
this.setFeature(InternalFeature.FRONT_MODIFIERS, null);
addFrontModifier(newFrontModifier);
}
/**
* Set the front modifier for this phrase. This resets all previous front
* modifiers to null
and replaces them with the given string.
*
* @param newFrontModifier the front modifier
*/
public void setFrontModifier(NLGElement newFrontModifier) {
this.setFeature(InternalFeature.FRONT_MODIFIERS, null);
addFrontModifier(newFrontModifier);
}
/**
* Adds a new pre-modifier to the phrase element.
*
* @param newPreModifier the new pre-modifier as an NLGElement
.
*/
public void addPreModifier(NLGElement newPreModifier) {
List preModifiers = getFeatureAsElementList(InternalFeature.PREMODIFIERS);
if(preModifiers == null) {
preModifiers = new ArrayList();
}
preModifiers.add(newPreModifier);
setFeature(InternalFeature.PREMODIFIERS, preModifiers);
}
/**
* Adds a new pre-modifier to the phrase element.
*
* @param newPreModifier the new pre-modifier as a String
. It is used to
* create a StringElement
.
*/
public void addPreModifier(String newPreModifier) {
addPreModifier(new StringElement(newPreModifier));
}
/**
* Set the premodifier for this phrase. This resets all previous
* premodifiers to null
and replaces them with the given
* string.
*
* @param newPreModifier the premodifier
*/
public void setPreModifier(String newPreModifier) {
this.setFeature(InternalFeature.PREMODIFIERS, null);
addPreModifier(newPreModifier);
}
/**
* Set the premodifier for this phrase. This resets all previous
* premodifiers to null
and replaces them with the given
* string.
*
* @param newPreModifier the premodifier
*/
public void setPreModifier(NLGElement newPreModifier) {
this.setFeature(InternalFeature.PREMODIFIERS, null);
addPreModifier(newPreModifier);
}
/**
* Add a modifier to a phrase Use heuristics to decide where it goes
*/
public void addModifier(Object modifier) {
// default addModifier - always make modifier a preModifier
if(modifier == null)
return;
// assume is preModifier, add in appropriate form
if(modifier instanceof NLGElement)
addPreModifier((NLGElement) modifier);
else
addPreModifier((String) modifier);
return;
}
/**
* Retrieves the current list of pre-modifiers for the phrase.
*
* @return a List
of NLGElement
s.
*/
public List getPreModifiers() {
return getFeatureAsElementList(InternalFeature.PREMODIFIERS);
}
/**
* Retrieves the current list of post modifiers for the phrase.
*
* @return a List
of NLGElement
s.
*/
public List getPostModifiers() {
return getFeatureAsElementList(InternalFeature.POSTMODIFIERS);
}
/**
* Retrieves the current list of frony modifiers for the phrase.
*
* @return a List
of NLGElement
s.
*/
public List getFrontModifiers() {
return getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS);
}
@Override
public String printTree(String indent) {
String thisIndent = indent == null ? " |-" : indent + " |-"; //$NON-NLS-1$ //$NON-NLS-2$
String childIndent = indent == null ? " | " : indent + " | "; //$NON-NLS-1$ //$NON-NLS-2$
String lastIndent = indent == null ? " \\-" : indent + " \\-"; //$NON-NLS-1$ //$NON-NLS-2$
String lastChildIndent = indent == null ? " " : indent + " "; //$NON-NLS-1$ //$NON-NLS-2$
StringBuffer print = new StringBuffer();
print.append("PhraseElement: category=") //$NON-NLS-1$
.append(getCategory().toString()).append(", features={"); //$NON-NLS-1$
Map features = getAllFeatures();
for(String eachFeature : features.keySet()) {
print.append(eachFeature).append('=').append(features.get(eachFeature).toString()).append(' ');
}
print.append("}\n"); //$NON-NLS-1$
List children = getChildren();
int length = children.size() - 1;
int index = 0;
for(index = 0; index < length; index++) {
print.append(thisIndent).append(children.get(index).printTree(childIndent));
}
if(length >= 0) {
print.append(lastIndent).append(children.get(length).printTree(lastChildIndent));
}
return print.toString();
}
/**
* Removes all existing complements on the phrase.
*/
public void clearComplements() {
removeFeature(InternalFeature.COMPLEMENTS);
}
/**
* Sets the determiner for the phrase. This only has real meaning on noun
* phrases and is added here for convenience. Determiners are some times
* referred to as specifiers.
*
* @param newDeterminer the new determiner for the phrase.
* @deprecated Use {@link NPPhraseSpec#setSpecifier(Object)} directly
*/
@Deprecated
public void setDeterminer(Object newDeterminer) {
NLGFactory factory = new NLGFactory();
NLGElement determinerElement = factory.createWord(newDeterminer, LexicalCategory.DETERMINER);
if(determinerElement != null) {
determinerElement.setFeature(InternalFeature.DISCOURSE_FUNCTION, DiscourseFunction.SPECIFIER);
setFeature(InternalFeature.SPECIFIER, determinerElement);
determinerElement.setParent(this);
}
}
}