//*****************************************************************************
/*
** FILE:   xm_AttToChildConverter.java
**
** (c) 1998 Steve Withall.
**
** HISTORY:
**    28Jun98  stevew  Created, based on xg_SimpleNodeFormatter.
**    05Jul98  stevew  Moved from package xg to xm.
*/
package xm;

import xg.xg_AttList;
import xg.xg_Attribute;
import xg.xg_Element;
import xg.xg_Node;
import xg.xg_Text;

//*****************************************************************************
/** <p>To create a child node for each of an xg_Node's attributes (and for
 *  those of all its descendants). The motivation for this is to make it easier
 *  to apply an XSL stylesheet to an XML document: it enables attribute values
 *  to be included in the results without resorting to the use of a scripting
 *  language. (This class has, however, been included in the xg package since
 *  it is not XSL-specific per se, and could conceivably be of use for other
 *  purposes.)</p>
 *
 *  <p>It applies the following rules:</p>
 *
 *  <LI>Apply these rules to each child element (ie. any node which is not an
 *      xg_Element is left unchanged), which will apply them to its children
 *      in turn. (Note that this is done before turning our attention to the
 *      node's attributes, to save us the trouble of applying these rules to
 *      the new child nodes which will result.)
 *
 *  <LI>For each of the node's attributes, create a new child element whose
 *      type is the name of the attribute, and whose content is the value of
 *      the attribute. The new children are placed at the beginning of the
 *      element's content. The preceding whitespace of each of these new children
 *      is set to be the same as that of its parent.
 *
 *  <p>Note that while this class implements the xg_NodeFormatter interface
 *  (because it is a convenient interface), this is not strictly just a
 *  formatter, because it makes significant changes to the structure of the
 *  node (typically a document) on which it is invoked.</p>
 */
public class xm_AttToChildConverter extends xm_NodeFormatter
{
    /** Control flag which specifies whether the type of each new child element
     *  has the name of its parent element prepended to it. If true, new child
     *  elements will have types of the form 'ParentAtt'; if false, the new child
     *  elements' type names will be the same as the names of the attributes from
     *  which they were generated. */
    boolean PrependParentNameFlag = true;

    //*****************************************************************************
    /** Convert the given node, and its children.
     *
     *  @param  InputNode          The node to convert
     *  @param  InputOpeningDepth  The depth of the node in the hierarchy. This
     *                              is ignored, and is present purely for
     *                              compatibility with xg_NodeFormatter.
     */
    public void format(xg_Node  InputNode, int  InputOpeningDepth)
    {
        // Convert each of this node's children.
        formatChildren(InputNode, InputOpeningDepth);

        // Only convert element nodes.
        if (InputNode instanceof xg.xg_Element)
        {
            // Process each of this element's attributes.
            xg_Element    CurrentElement = (xg_Element)InputNode;
            String        NewChildName   = null;
            xg_Element    NewChild       = null;
            xg_AttList    ElementAttList = CurrentElement.getAttList();
            xg_Attribute  CurrentAtt     = null;
            for (int  AttIndex = ElementAttList.getLength() - 1; AttIndex >= 0; AttIndex--)
            {
                CurrentAtt = ElementAttList.getAtt(AttIndex);

                if (PrependParentNameFlag)
                    NewChildName = CurrentElement.getName() + CurrentAtt.getName();
                else
                    NewChildName = CurrentAtt.getName();

                //TBD Do not add element if a child of this type is already present
                //TBD (to avoid duplication if the conversion is run again).
                NewChild   = new xg_Element(NewChildName);
                NewChild.setPrecedingWhitespace(CurrentElement.getPrecedingWhitespace() );
                NewChild.addChild(new xg_Text(CurrentAtt.getValue() ) );
                CurrentElement.insertChild(NewChild, 0);
            }
        }
    }

    //*****************************************************************************
    /** Set the value of the flag which determines whether elements generated
     *  from attributes have their parent's type prepended.
     *
     *  @param  PrependParentNameFlag  true if the parent's type is to be prepended;
     *                                  false if not
     */
    public void setPrependParentNameFlag(boolean  InputPrependParentNameFlag)
    {
        PrependParentNameFlag = InputPrependParentNameFlag;
    }

    //*****************************************************************************
    /** Get the value of the flag which determines whether elements generated
     *  from attributes have their parent's type prepended.
     *
     *  @return  true if the parent's type is prepended; false if not
     */
    public boolean getPrependParentNameFlag()
    {
        return PrependParentNameFlag;
    }
}

//*****************************************************************************
