Exemple #1
0
        /**
         * Perform aggregation on a single phrase. This method only works on a
         * {@link simplenlg.framework.CoordinatedPhraseElement}, in which case it
         * calls {@link #apply(List)} on the children of the coordinated phrase,
         * returning a coordinated phrase whose children are the result.
         *
         * @param phrase
         * @return aggregated result
         */
        public virtual NLGElement apply(NLGElement phrase)
        {
            NLGElement result = null;

            if (phrase is CoordinatedPhraseElement)
            {
                IList <NLGElement> children   = ((CoordinatedPhraseElement)phrase).Children;
                IList <NLGElement> aggregated = apply(children);

                if (aggregated.Count == 1)
                {
                    result = aggregated[0];
                }
                else
                {
                    result = factory.createCoordinatedPhrase();

                    foreach (NLGElement agg in aggregated)
                    {
                        ((CoordinatedPhraseElement)result).addCoordinate(agg);
                    }
                }
            }


            if (result != null)
            {
                foreach (string feature in phrase.AllFeatureNames)
                {
                    result.setFeature(feature, phrase.getFeature(feature));
                }
            }

            return(result);
        }
        /**
         * Applies aggregation to two NLGElements e1 and e2, succeeding only if they
         * are clauses (that is, e1.getCategory() == e2.getCategory ==
         * {@link simplenlg.framework.PhraseCategory#CLAUSE}).
         */
        public override NLGElement apply(NLGElement previous, NLGElement next)
        {
            NLGElement aggregated = null;

            if (previous.Category == PhraseCategory.PhraseCategoryEnum.CLAUSE && next.Category == PhraseCategory.PhraseCategoryEnum.CLAUSE && PhraseChecker.nonePassive(previous, next) && !PhraseChecker.expletiveSubjects(previous, next))
            {
                if (PhraseChecker.sameSentences(previous, next))
                {                 // case 1: identical sentences: remove the current
                    aggregated = previous;
                }
                else if (PhraseChecker.sameFrontMods(previous, next) && PhraseChecker.sameSubjects(previous, next) && PhraseChecker.samePostMods(previous, next))
                {                 // case 2: subjects identical: coordinate VPs
                    aggregated = factory.createClause();
                    aggregated.setFeature(InternalFeature.SUBJECTS, previous.getFeatureAsElementList(InternalFeature.SUBJECTS));
                    aggregated.setFeature(InternalFeature.FRONT_MODIFIERS, previous.getFeatureAsElement(InternalFeature.FRONT_MODIFIERS));
                    aggregated.setFeature(Feature.CUE_PHRASE, previous.getFeatureAsElement(Feature.CUE_PHRASE));
                    aggregated.setFeature(InternalFeature.POSTMODIFIERS, previous.getFeatureAsElementList(InternalFeature.POSTMODIFIERS));
                    NLGElement vp;

                    if (!PhraseChecker.sameVPArgs(previous, next) && PhraseChecker.sameVPHead(previous, next) && PhraseChecker.sameVPModifiers(previous, next))
                    {                     // case 2.1: VPs have different arguments but same head & mods
                        NLGElement vp1 = previous.getFeatureAsElement(InternalFeature.VERB_PHRASE);
                        vp = factory.createVerbPhrase();
                        vp.setFeature(InternalFeature.HEAD, vp1.getFeatureAsElement(InternalFeature.HEAD));
                        vp.setFeature(InternalFeature.COMPLEMENTS, vp1.getFeatureAsElementList(InternalFeature.COMPLEMENTS));
                        vp.setFeature(InternalFeature.PREMODIFIERS, vp1.getFeatureAsElementList(InternalFeature.PREMODIFIERS));
                        vp.setFeature(InternalFeature.POSTMODIFIERS, vp1.getFeatureAsElementList(InternalFeature.POSTMODIFIERS));
                    }
                    else
                    {                     // case 2.2: just create a coordinate vP
                        NLGElement vp1 = previous.getFeatureAsElement(InternalFeature.VERB_PHRASE);
                        NLGElement vp2 = next.getFeatureAsElement(InternalFeature.VERB_PHRASE);
                        vp = factory.createCoordinatedPhrase(vp1, vp2);
                    }
                    // case 2.3: expletive subjects
                    aggregated.setFeature(InternalFeature.VERB_PHRASE, vp);
                }
                else if (PhraseChecker.sameFrontMods(previous, next) && PhraseChecker.sameVP(previous, next) && PhraseChecker.samePostMods(previous, next))
                {                 // case 3: identical VPs: conjoin subjects and front modifiers
                    aggregated = factory.createClause();
                    aggregated.setFeature(InternalFeature.FRONT_MODIFIERS, previous.getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS));
                    CoordinatedPhraseElement subjects = factory.createCoordinatedPhrase();
                    subjects.Category = new PhraseCategory(PhraseCategory.PhraseCategoryEnum.NOUN_PHRASE);
                    IList <NLGElement> allSubjects = previous.getFeatureAsElementList(InternalFeature.SUBJECTS);
                    ((List <NLGElement>)allSubjects).AddRange(next.getFeatureAsElementList(InternalFeature.SUBJECTS));

                    foreach (NLGElement subj in allSubjects)
                    {
                        subjects.addCoordinate(subj);
                    }

                    aggregated.setFeature(InternalFeature.SUBJECTS, subjects);
                    aggregated.setFeature(InternalFeature.POSTMODIFIERS, previous.getFeatureAsElementList(InternalFeature.POSTMODIFIERS));
                    aggregated.setFeature(InternalFeature.VERB_PHRASE, previous.getFeature(InternalFeature.VERB_PHRASE));
                }
            }

            return(aggregated);
        }
 /* (non-Javadoc)
  * @see simplenlg.framework.NLGElement#getFeature(java.lang.String)
  */
 public override object getFeature(string featureName)
 {
     if (base.getFeature(featureName) != null)
     {
         return(base.getFeature(featureName));
     }
     if (vpFeatures.Contains(featureName))
     {
         NLGElement verbPhrase = (NLGElement)getFeatureAsElement(InternalFeature.VERB_PHRASE);
         if (verbPhrase != null || verbPhrase is VPPhraseSpec)
         {
             return(verbPhrase.getFeature(featureName));
         }
     }
     return(null);
 }
Exemple #4
0
        /**
         * Retrieves the correct representation of the word from the element. This
         * method will find the <code>WordElement</code>, if it exists, for the
         * given phrase or inflected word.
         *
         * @param element
         *            the <code>NLGElement</code> from which the head is required.
         * @return the <code>WordElement</code>
         */
        private static WordElement getHeadWordElement(NLGElement element)
        {
            WordElement head = null;

            if (element is WordElement)
            {
                head = (WordElement)element;
            }
            else if (element is InflectedWordElement)
            {
                head = (WordElement)element.getFeature(InternalFeature.BASE_WORD);
            }
            else if (element is PhraseElement)
            {
                head = getHeadWordElement(((PhraseElement)element).getHead());
            }

            return(head);
        }
        /**
         * Checks to see if any of the complements to the phrase are plural.
         *
         * @param complements
         *            the list of complements of the phrase.
         * @return <code>true</code> if any of the complements are plural.
         */
        private static bool hasPluralComplement(IList <NLGElement> complements)
        {
            bool plural = false;
            IEnumerator <NLGElement> complementIterator = complements.GetEnumerator();
            NLGElement eachComplement = null;
            object     numberValue    = null;

            while (complementIterator.MoveNext() && !plural)
            {
                eachComplement = complementIterator.Current;

                if (eachComplement != null && eachComplement.isA(new PhraseCategory(PhraseCategory.PhraseCategoryEnum.NOUN_PHRASE)))
                {
                    numberValue = eachComplement.getFeature(Feature.NUMBER);
                    if (numberValue != null && NumberAgreement.PLURAL.Equals(numberValue))
                    {
                        plural = true;
                    }
                }
            }
            return(plural);
        }
        public static IList <FunctionalSet> collectFunctionalPairs(NLGElement phrase1, NLGElement phrase2)
        {
            IList <NLGElement>    children1 = getAllChildren(phrase1);
            IList <NLGElement>    children2 = getAllChildren(phrase2);
            IList <FunctionalSet> pairs     = new List <FunctionalSet>();

            if (children1.Count == children2.Count)
            {
                Periphery periph = Periphery.LEFT;

                for (int i = 0; i < children1.Count; i++)
                {
                    NLGElement        child1 = children1[i];
                    NLGElement        child2 = children2[i];
                    ElementCategory   cat1   = child1.Category;
                    ElementCategory   cat2   = child2.Category;
                    DiscourseFunction func1  = (DiscourseFunction)child1.getFeature(InternalFeature.DISCOURSE_FUNCTION);
                    DiscourseFunction func2  = (DiscourseFunction)child2.getFeature(InternalFeature.DISCOURSE_FUNCTION);

                    if (cat1 == cat2 && func1 == func2)
                    {
                        pairs.Add(FunctionalSet.newInstance(func1, cat1, periph, child1, child2));

                        if (cat1 == LexicalCategory.LexicalCategoryEnum.VERB)
                        {
                            periph = Periphery.RIGHT;
                        }
                    }
                    else
                    {
                        pairs.Clear();
                        break;
                    }
                }
            }

            return(pairs);
        }
Exemple #7
0
        /**
         * Realises coordinated phrases. Where there are more than two coordinates,
         * then a comma replaces the conjunction word between all the coordinates
         * save the last two. For example, <em>John and Peter and Simon</em> becomes
         * <em>John, Peter and Simon</em>.
         *
         * @param components
         *            the <code>List</code> of <code>NLGElement</code>s representing
         *            the components that make up the sentence.
         * @return the realised element as an <code>NLGElement</code>.
         */
        private NLGElement realiseCoordinatedPhrase(IList <NLGElement> components)
        {
            StringBuilder realisation   = new StringBuilder();
            NLGElement    realisedChild = null;

            int length = components.Count;

            for (int index = 0; index < length; index++)
            {
                realisedChild = components[index];
                if (index < length - 2 && DiscourseFunction.CONJUNCTION.Equals(realisedChild.getFeature(InternalFeature.DISCOURSE_FUNCTION)))
                {
                    realisation.Append(", ");                     //$NON-NLS-1$
                }
                else
                {
                    realisedChild = realise(realisedChild);
                    realisation.Append(realisedChild.Realisation).Append(' ');
                }
            }
            realisation.Length = realisation.Length - 1;
            return(new StringElement(realisation.ToString().Replace(" ,", ",")));            //$NON-NLS-1$ //$NON-NLS-2$
        }
Exemple #8
0
        /**
         * Checks the subjects of the phrase to determine if there is more than one
         * subject. This ensures that the verb phrase is correctly set. Also set
         * person correctly
         *
         * @param phrase
         *            the <code>PhraseElement</code> representing this clause.
         * @param verbElement
         *            the <code>NLGElement</code> representing the verb phrase for
         *            this clause.
         */
        private static void checkSubjectNumberPerson(PhraseElement phrase, NLGElement verbElement)
        {
            NLGElement         currentElement = null;
            IList <NLGElement> subjects       = phrase.getFeatureAsElementList(InternalFeature.SUBJECTS);
            bool   pluralSubjects             = false;
            Person?person = null;

            if (subjects != null)
            {
                switch (subjects.Count)
                {
                case 0:
                    break;

                case 1:
                    currentElement = subjects[0];
                    // coordinated NP with "and" are plural (not coordinated NP with "or")
                    if (currentElement is CoordinatedPhraseElement && ((CoordinatedPhraseElement)currentElement).checkIfPlural())
                    {
                        pluralSubjects = true;
                    }
                    else if (((NumberAgreement?)currentElement.getFeature(Feature.NUMBER) == NumberAgreement.PLURAL) && !(currentElement is SPhraseSpec))                     // ER mod-
                    {
                        // ER mod-clauses are singular as NPs, even if they are plural internally
                        pluralSubjects = true;
                    }
                    else if (currentElement.isA(new PhraseCategory(PhraseCategory.PhraseCategoryEnum.NOUN_PHRASE)))
                    {
                        NLGElement currentHead = currentElement.getFeatureAsElement(InternalFeature.HEAD);
                        person = (Person?)currentElement.getFeature(Feature.PERSON);

                        if (currentHead == null)
                        {
                            // subject is null and therefore is not gonna be plural
                            pluralSubjects = false;
                        }
                        else if ((NumberAgreement?)currentHead.getFeature(Feature.NUMBER) == NumberAgreement.PLURAL)
                        {
                            pluralSubjects = true;
                        }
                        else if (currentHead is ListElement)
                        {
                            pluralSubjects = true;

                            /*
                             * } else if (currentElement instanceof
                             * CoordinatedPhraseElement &&
                             * "and".equals(currentElement.getFeatureAsString(
                             * //$NON-NLS-1$ Feature.CONJUNCTION))) { pluralSubjects
                             * = true;
                             */
                        }
                    }
                    break;

                default:
                    pluralSubjects = true;
                    break;
                }
            }
            if (verbElement != null)
            {
                verbElement.setFeature(Feature.NUMBER, pluralSubjects ? NumberAgreement.PLURAL : (NumberAgreement?)phrase.getFeature(Feature.NUMBER));
                if (person != null)
                {
                    verbElement.setFeature(Feature.PERSON, person);
                }
            }
        }
Exemple #9
0
        /**
         * ~Set the features for a sentence. This method also checks whether any
         * features have been set on the VP, in which case, they are set if they
         * haven't been set on the S
         *
         * @param wp
         *            the xml SPhraseSpec object
         * @param sp
         *            the sentence.
         * @param vp
         *            the verb phrase.
         */
        private void setSFeatures(wrapper.XmlSPhraseSpec wp, SPhraseSpec sp, NLGElement vp)
        {
            if (wp.CLAUSESTATUS != null)
            {
                Enum.TryParse(wp.CLAUSESTATUS.ToString(), out ClauseStatus clauseStatus);
                sp.setFeature(InternalFeature.CLAUSE_STATUS, clauseStatus);
            }

            if (wp.PERSON != null)
            {
                Enum.TryParse(wp.PERSON.ToString(), out Person person);
                sp.setFeature(Feature.PERSON, person);
            }

            if (wp.FORM != null)
            {
                Enum.TryParse(wp.FORM.ToString(), out Form form);
                sp.setFeature(Feature.FORM, form);
            }

            if (wp.TENSE != null)
            {
                Enum.TryParse(wp.TENSE.ToString(), out Form tense);
                sp.setFeature(Feature.TENSE, tense);
            }
            else if (vp != null && vp.hasFeature(Feature.TENSE))
            {
                sp.setFeature(Feature.TENSE, vp.getFeature(Feature.TENSE));
            }

            // modal -- set on S or inherited from VP
            if (wp.MODAL != null)
            {
                sp.setFeature(Feature.MODAL, wp.MODAL);
            }
            else if (vp != null && vp.hasFeature(Feature.MODAL))
            {
                sp.setFeature(Feature.MODAL, vp.getFeature(Feature.MODAL));
            }

            // interrogative
            if (wp.INTERROGATIVETYPE != null)
            {
                Enum.TryParse(wp.INTERROGATIVETYPE.ToString(), out InterrogativeType interrogativeType);
                sp.setFeature(Feature.INTERROGATIVE_TYPE, interrogativeType);
            }
            else if (vp != null && vp.hasFeature(Feature.INTERROGATIVE_TYPE))
            {
                sp.setFeature(Feature.INTERROGATIVE_TYPE, vp.getFeature(Feature.INTERROGATIVE_TYPE));
            }

            // set on clauses.
            bool sAggregateAuxiliary = wp.AGGREGATEAUXILIARY ?? false;
            bool vAggregateAuxiliary = vp?.getFeatureAsBoolean(Feature.AGGREGATE_AUXILIARY) ?? false;

            sp.setFeature(Feature.AGGREGATE_AUXILIARY, sAggregateAuxiliary || vAggregateAuxiliary);

            // passive: can be set on S or VP
            bool sPass = wp.PASSIVE ?? false;
            bool vPass = vp?.getFeatureAsBoolean(Feature.PASSIVE) ?? false;

            sp.setFeature(Feature.PASSIVE, sPass || vPass);

            // progressive: can be set on S or VP
            bool sProg = wp.PROGRESSIVE ?? false;
            bool vProg = vp?.getFeatureAsBoolean(Feature.PROGRESSIVE) ?? false;

            sp.setFeature(Feature.PROGRESSIVE, sProg || vProg);

            // perfect: can be set on S or VP
            bool sPerf = wp.PERFECT ?? false;
            bool vPerf = vp?.getFeatureAsBoolean(Feature.PERFECT) ?? false;

            sp.setFeature(Feature.PERFECT, sPerf || vPerf);

            // negation: can be set on S or VP
            bool sNeg = wp.NEGATED ?? false;
            bool vNeg = vp?.getFeatureAsBoolean(Feature.NEGATED) ?? false;

            sp.setFeature(Feature.NEGATED, sNeg || vNeg);

            // set on clauses.
            bool ssgg = wp.SUPPRESSGENITIVEINGERUND ?? false;
            bool vsgg = vp?.getFeatureAsBoolean(Feature.SUPPRESS_GENITIVE_IN_GERUND) ?? false;

            sp.setFeature(Feature.SUPPRESS_GENITIVE_IN_GERUND, ssgg || vsgg);

            // set on clauses.
            bool ssc = wp.SUPRESSEDCOMPLEMENTISER ?? false;
            bool vsc = vp?.getFeatureAsBoolean(Feature.SUPRESSED_COMPLEMENTISER) ?? false;

            sp.setFeature(Feature.SUPRESSED_COMPLEMENTISER, ssc || vsc);
        }
        public override IList <NLGElement> realise(IList <NLGElement> elements)
        {
            IList <NLGElement> realisedElements = new List <NLGElement>();
            NLGElement         currentElement   = null;
            NLGElement         determiner       = null;
            NLGElement         prevElement      = null;

            if (elements != null)
            {
                foreach (NLGElement eachElement in elements)
                {
                    currentElement = realise(eachElement);

                    if (currentElement != null)
                    {
                        //pass the discourse function and appositive features -- important for orth processor
                        currentElement.setFeature(Feature.APPOSITIVE, eachElement.getFeature(Feature.APPOSITIVE));
                        object function = eachElement.getFeature(InternalFeature.DISCOURSE_FUNCTION);

                        if (function != null)
                        {
                            currentElement.setFeature(InternalFeature.DISCOURSE_FUNCTION, function);
                        }

                        if (prevElement != null && prevElement is StringElement && eachElement is InflectedWordElement && ((InflectedWordElement)eachElement).Category == LexicalCategory.LexicalCategoryEnum.NOUN)
                        {
                            string prevString = prevElement.Realisation;

                            //realisedElements.get(realisedElements.size() - 1)

                            prevElement.Realisation = DeterminerAgrHelper.checkEndsWithIndefiniteArticle(prevString, currentElement.Realisation);
                        }

                        // realisedElements.add(realise(currentElement));
                        realisedElements.Add(currentElement);

                        if (determiner == null && DiscourseFunction.SPECIFIER.Equals(currentElement.getFeature(InternalFeature.DISCOURSE_FUNCTION)))
                        {
                            determiner = currentElement;
                            determiner.setFeature(Feature.NUMBER, eachElement.getFeature(Feature.NUMBER));
                            // MorphologyRules.doDeterminerMorphology(determiner,
                            // currentElement.getRealisation());
                        }
                        else if (determiner != null)
                        {
                            if (currentElement is ListElement)
                            {
                                // list elements: ensure det matches first element
                                NLGElement firstChild = ((ListElement)currentElement).Children[0];

                                if (firstChild != null)
                                {
                                    //AG: need to check if child is a coordinate
                                    if (firstChild is CoordinatedPhraseElement)
                                    {
                                        MorphologyRules.doDeterminerMorphology(determiner, firstChild.Children[0].Realisation);
                                    }
                                    else
                                    {
                                        MorphologyRules.doDeterminerMorphology(determiner, firstChild.Realisation);
                                    }
                                }
                            }
                            else
                            {
                                // everything else: ensure det matches realisation
                                MorphologyRules.doDeterminerMorphology(determiner, currentElement.Realisation);
                            }

                            determiner = null;
                        }
                    }
                    prevElement = eachElement;
                }
            }

            return(realisedElements);
        }
        public override NLGElement realise(NLGElement element)
        {
            NLGElement realisedElement = null;

            if (element != null && !element.getFeatureAsBoolean(Feature.ELIDED))
            {
                if (element is DocumentElement)
                {
                    IList <NLGElement> children = element.Children;
                    ((DocumentElement)element).Components = realise(children);
                    realisedElement = element;
                }
                else if (element is PhraseElement)
                {
                    realisedElement = realisePhraseElement((PhraseElement)element);
                }
                else if (element is ListElement)
                {
                    realisedElement = new ListElement();
                    ((ListElement)realisedElement).addComponents(realise(element.Children));
                }
                else if (element is InflectedWordElement)
                {
                    string          baseForm = ((InflectedWordElement)element).BaseForm;
                    ElementCategory category = element.Category;

                    if (lexicon != null && !ReferenceEquals(baseForm, null))
                    {
                        WordElement word = ((InflectedWordElement)element).BaseWord;

                        if (word == null)
                        {
                            if (category is LexicalCategory)
                            {
                                word = lexicon.lookupWord(baseForm, (LexicalCategory)category);
                            }
                            else
                            {
                                word = lexicon.lookupWord(baseForm);
                            }
                        }

                        if (word != null)
                        {
                            ((InflectedWordElement)element).BaseWord = word;
                        }
                    }

                    realisedElement = element;
                }
                else if (element is WordElement)
                {
                    // AG: need to check if it's a word element, in which case it
                    // needs to be marked for inflection
                    InflectedWordElement infl = new InflectedWordElement((WordElement)element);


                    // the inflected word inherits all features from the base word
                    foreach (string feature in element.AllFeatureNames)
                    {
                        infl.setFeature(feature, element.getFeature(feature));
                    }

                    realisedElement = realise(infl);
                }
                else if (element is CoordinatedPhraseElement)
                {
                    realisedElement = CoordinatedPhraseHelper.realise(this, (CoordinatedPhraseElement)element);
                }
                else
                {
                    realisedElement = element;
                }
            }

            // Remove the spurious ListElements that have only one element.
            if (realisedElement is ListElement)
            {
                if (((ListElement)realisedElement).size() == 1)
                {
                    realisedElement = ((ListElement)realisedElement).First;
                }
            }

            return(realisedElement);
        }
Exemple #12
0
        public override NLGElement realise(NLGElement element)
        {
            NLGElement realisedElement = null;
            object     function        = null;  //the element's discourse function

            //get the element's function first
            if (element is ListElement)
            {
                IList <NLGElement> children = element.Children;
                if (children.Any())
                {
                    NLGElement firstChild = children[0];
                    function = firstChild.getFeature(InternalFeature.DISCOURSE_FUNCTION);
                }
            }
            else
            {
                if (element != null)
                {
                    function = element.getFeature(InternalFeature.DISCOURSE_FUNCTION);
                }
            }

            if (element != null)
            {
                ElementCategory category = element.Category;

                if (category is DocumentCategory && element is DocumentElement)
                {
                    IList <NLGElement> components = ((DocumentElement)element).Components;

                    switch (((DocumentCategory)category).GetDocumentCategory())
                    {
                    case DocumentCategory.DocumentCategoryEnum.SENTENCE:
                        realisedElement = realiseSentence(components, element);
                        break;

                    case DocumentCategory.DocumentCategoryEnum.LIST_ITEM:
                        if (components != null && components.Any())
                        {
                            // recursively realise whatever is in the list item
                            // NB: this will realise embedded lists within list items
                            realisedElement        = new ListElement(realise(components));
                            realisedElement.Parent = element.Parent;
                        }
                        break;

                    default:
                        ((DocumentElement)element).Components = realise(components);
                        realisedElement = element;
                        break;
                    }
                }
                else if (element is ListElement)
                {
                    // AG: changes here: if we have a premodifier, then we ask the
                    // realiseList method to separate with a comma.
                    // if it's a postmod, we need commas at the start and end only
                    // if it's appositive
                    StringBuilder buffer = new StringBuilder();

                    if (DiscourseFunction.PRE_MODIFIER.Equals(function))
                    {
                        bool all_appositives = true;
                        foreach (NLGElement child in element.Children)
                        {
                            all_appositives = all_appositives && child.getFeatureAsBoolean(Feature.APPOSITIVE);
                        }

                        // TODO: unless this is the end of the sentence
                        if (all_appositives)
                        {
                            buffer.Append(", ");
                        }
                        realiseList(buffer, element.Children, commaSepPremodifiers ? "," : "");
                        if (all_appositives)
                        {
                            buffer.Append(", ");
                        }
                    }
                    else if (DiscourseFunction.POST_MODIFIER.Equals(function))
                    {                     // && appositive)
                        IList <NLGElement> postmods = element.Children;
                        // bug fix due to Owen Bennett
                        int len = postmods.Count;

                        for (int i = 0; i < len; i++)
                        {
                            // for(NLGElement postmod: element.getChildren()) {
                            NLGElement postmod = postmods[i];

                            // if the postmod is appositive, it's sandwiched in commas
                            if (postmod.getFeatureAsBoolean(Feature.APPOSITIVE))
                            {
                                buffer.Append(", ");
                                buffer.Append(realise(postmod));
                                buffer.Append(", ");
                            }
                            else
                            {
                                buffer.Append(realise(postmod));
                                if (postmod is ListElement || (postmod.Realisation != null && !postmod.Realisation.Equals("")))
                                {
                                    buffer.Append(" ");
                                }
                            }
                        }
                    }
                    else if ((DiscourseFunction.CUE_PHRASE.Equals(function) || DiscourseFunction.FRONT_MODIFIER.Equals(function)) && commaSepCuephrase)
                    {
                        realiseList(buffer, element.Children, commaSepCuephrase ? "," : "");
                    }
                    else
                    {
                        realiseList(buffer, element.Children, "");
                    }

                    // realiseList(buffer, element.getChildren(), "");
                    realisedElement = new StringElement(buffer.ToString());
                }
                else if (element is CoordinatedPhraseElement)
                {
                    realisedElement = realiseCoordinatedPhrase(element.Children);
                }
                else
                {
                    realisedElement = element;
                }

                // make the realised element inherit the original category
                // essential if list items are to be properly formatted later
                if (realisedElement != null)
                {
                    realisedElement.Category = category;
                }

                //check if this is a cue phrase; if param is set, postfix a comma
                if ((DiscourseFunction.CUE_PHRASE.Equals(function) || DiscourseFunction.FRONT_MODIFIER.Equals(function)) && commaSepCuephrase)
                {
                    string realisation = realisedElement.Realisation;

                    if (!realisation.EndsWith(",", StringComparison.Ordinal))
                    {
                        realisation = realisation + ",";
                    }

                    realisedElement.Realisation = realisation;
                }
                if (element.Capitalized)
                {
                    string realisation = realisedElement.Realisation;
                    realisedElement.Realisation = realisation.Substring(0, 1).ToUpper() + realisation.Substring(1);
                }
            }
            //remove preceding and trailing whitespace from internal punctuation
            removePunctSpace(realisedElement);
            return(realisedElement);
        }
        /**
         * Determines the number agreement for the phrase ensuring that any number
         * agreement on the parent element is inherited by the phrase.
         *
         * @param parent
         *            the parent element of the phrase.
         * @param phrase
         *            the <code>PhraseElement</code> representing this noun phrase.
         * @return the <code>NumberAgreement</code> to be used for the phrase.
         */
        private static NumberAgreement?determineNumber(NLGElement parent, PhraseElement phrase)
        {
            object          numberValue = phrase.getFeature(Feature.NUMBER);
            NumberAgreement?number      = null;

            if (numberValue != null && numberValue is NumberAgreement)
            {
                number = (NumberAgreement)numberValue;
            }
            else
            {
                number = NumberAgreement.SINGULAR;
            }

            // Ehud Reiter = modified below to force number from VP for WHAT_SUBJECT
            // and WHO_SUBJECT interrogatuves
            if (parent is PhraseElement)
            {
                if (parent.isA(new PhraseCategory(PhraseCategory.PhraseCategoryEnum.CLAUSE)) && (PhraseHelper.isExpletiveSubject((PhraseElement)parent) || InterrogativeType.WHO_SUBJECT.Equals(parent.getFeature(Feature.INTERROGATIVE_TYPE)) || InterrogativeType.WHAT_SUBJECT.Equals(parent.getFeature(Feature.INTERROGATIVE_TYPE))) && isCopular(phrase.getHead()))
                {
                    if (hasPluralComplement(phrase.getFeatureAsElementList(InternalFeature.COMPLEMENTS)))
                    {
                        number = NumberAgreement.PLURAL;
                    }
                    else
                    {
                        number = NumberAgreement.SINGULAR;
                    }
                }
            }
            return(number);
        }