Pad

/* Recursively pads a space to one side of the passed "s"
    "i" is the index - how many to add
    "d" is the direction - if d is missing or not right, assumes left padding
    could be redone to include being passed the padding character

    original method:
     function PadLeft(s,i){ return ( i>=1 ) ? (" "+s,i-1,d) :s; }

  */
<script type="text/javascript">
    function Pad(s,i,d){
        return ( i>=1 )
                  ? Pad(((d!=null && d.toLowerCase()=="r")?s+" ":" "+s),i-1,d)
                   :s;
    }
</script>

nextTag


/// <summary>Recursively populates the next-highest tag</summary>
private tag nextTag(string textBlock, int depth)
{
    int startIndex = textBlock.IndexOf('>');
    tag newTag = new tag(textBlock.Substring(1, startIndex-1), depth);
    int endIndex = textBlock.IndexOf("</" + newTag.name + ">");
    bool haveEmptyTag = endIndex == startIndex + 1;

    List<string> contents = new List<string>();
    List<tag> tagChildren = new List<tag>();

    string stringFormat = "";

    if ( haveEmptyTag ) { return newTag; }
    else
    {
        string remainingInternals = textBlock.Substring(startIndex + 1, endIndex - startIndex - 1);

        int firstThan = -2;
        int lastThan = -2;
        int nextThan = -2;
        int afterEndThan = -2;

        bool haveContentOrTags = false;
        bool haveContent = false;
        bool haveTag = false;
       
        string nameAttr = "";
        string tagName = "";
        string tagEnd = "";
        string tagBlock = "";

        string content = "";

        haveContentOrTags = remainingInternals.Length > 0;
        while (haveContentOrTags)
        {
            firstThan = remainingInternals.IndexOf("<");
            lastThan = remainingInternals.IndexOf(">");
            nextThan = lastThan + 1;
            haveTag = firstThan > -1;
            haveContent = (!haveTag || (haveTag && firstThan>0));

            if (haveContent)
            {
                if (lastThan > -1)
                {
                    nextThan = remainingInternals.Substring(lastThan).IndexOf('<') + lastThan;
                }

                content = (!haveTag)
                        ? remainingInternals
                        : remainingInternals.Substring(lastThan + 1, nextThan - lastThan - 1);

                if (content.Length > 0)
                {
                    contents.Add(content);
                    stringFormat += "c" + contents.Count;
                    remainingInternals = remainingInternals.Substring(content.Length);
                }
            }

            // continuing so we look for a tag
            // note: remainingInternals, at this point, should start with a ">"
            if (haveTag && remainingInternals.Length > 0)
            {
                lastThan = remainingInternals.IndexOf(">");
                nameAttr = remainingInternals.Substring(1, lastThan - 1);
                tagName = nameAttr;
                if (tagName.IndexOf(" ") > -1) { tagName = tagName.Substring(0, tagName.IndexOf(" ")); }
                tagEnd = "</" + tagName + ">";
                afterEndThan = remainingInternals.IndexOf(tagEnd) + tagEnd.Length;
                tagBlock = remainingInternals.Substring(0, afterEndThan);
                tagChildren.Add(nextTag(tagBlock, depth+1));
                stringFormat += "t" + tagChildren.Count;
                remainingInternals = remainingInternals.Substring(tagBlock.Length);
            }
            haveContentOrTags = remainingInternals.Length > 0;
        }
        newTag.contents = contents;
        newTag.tagChildren = tagChildren;
        newTag.stringFormat = stringFormat;
    }
    return newTag;
}

tag


public class tag
{
    public string name;
    public string id;
    public tagType type;
    public Dictionary<String, String> attributes;
    public List<string> contents;
    public List<tag> tagChildren;
    public string stringFormat;
    public string content;
    public int depth;

    public tag() { }
 
    public tag( string initialtag )
    {
        type = (initialtag.IndexOf("/")>=0) ? tagType.close : tagType.open;
        depth = 0;
        instantiateParameters();
        PopulateAttributes(initialtag.Replace("/", ""));
    }

    public tag(string initialtag, int d)
    {
        type = (initialtag.IndexOf("/") >= 0) ? tagType.close : tagType.open;
        depth = d;
        instantiateParameters();
        PopulateAttributes(initialtag.Replace("/", ""));
    }

    private void instantiateParameters()
    {
        attributes = new Dictionary<String, String>();
        contents = new List<string>();
        stringFormat = "";
        tagChildren = new List<tag>();
    }

    private void PopulateAttributes(string tagItem)
    {
        int firstSpace = tagItem.IndexOf(" ");
        bool haveAttributes = firstSpace > -1;
        string name = tagItem;
        string[] potAttr;
        string key;
        string value;
        if( haveAttributes )
        {
            name = tagItem.Substring(0, firstSpace);
            potAttr = tagItem.Substring(firstSpace).Split(' ');
            foreach( string attr in potAttr)
            {
                if (attr != "")
                {
                    key = attr.Split('=')[0];
                    value = attr.Split('=')[1];
                    attributes.Add(key, value);
                }
            }
        }
        this.name = name;
    }
}

tagType

public enum tagType { open, close }