5
\$\begingroup\$

I find the TagBuilder written in C# little poor without the ability to "host" inside it sub tags (as objects not as strings).

So I wrote a simple class that inherits TagBuilder and allow to save sub tags. I can navigate inside it and add things to it while I move across the application. And when I call the Top Tag Object .ToString, it will render the entire html

public class MultiLevelHtmlTag : TagBuilder
{
    public MultiLevelHtmlTag(string tagName) : base(tagName) { }

    public List<MultiLevelHtmlTag> InnerTags = new List<MultiLevelHtmlTag>();



    public override string ToString()
    {
        if (InnerTags.Count > 0)
        {
            foreach (MultiLevelHtmlTag tag in InnerTags)
            {
                this.InnerHtml += tag.ToString();
            }
        }
        return base.ToString();
    }
}

this is how I use it:

MultiLevelHtmlTag top = new MultiLevelHtmlTag("div");
top.InnerTags.Add(new MultiLevelHtmlTag("span"));
log.Debug(top.ToString());

output:

<div><span></span></div>

What do you think about it? is that a goot pattern?

\$\endgroup\$
2
  • \$\begingroup\$ I would create a separate class for all valid HTML tags, and apply the Composite pattern. \$\endgroup\$ Commented Oct 22, 2011 at 21:03
  • 2
    \$\begingroup\$ You have some fundamental issues in your code. Your ToString() method has some major problems. See what happens if you call it multiple times. It should only return a string representation of the object. It shouldn't be modifying it. \$\endgroup\$ Commented Oct 23, 2011 at 0:44

1 Answer 1

6
\$\begingroup\$

I would make sure the list is not exposed publicly - the caller can then do whatever they want with that list, even assign null to it. So I've refactored it a little bit and implemented Add() (you may also want to implement Remove(), etc.):

/// <summary>
/// Simple class that inherits TagBuilder and allow to save sub tags.
/// </summary>
public class MultiLevelHtmlTag : TagBuilder
{
    /// <summary>
    /// List of inner tags.
    /// </summary>
    private readonly IList<MultiLevelHtmlTag> innerTags = new List<MultiLevelHtmlTag>();

    /// <summary>
    /// Initializes a new instance of the <see cref="MultiLevelHtmlTag"/> class.
    /// </summary>
    /// <param name="tagName">The name of the tag.</param>
    public MultiLevelHtmlTag(string tagName) : base(tagName)
    {
    }

    /// <summary>
    /// Gets the inner tag list.
    /// </summary>
    /// <value>The inner tag list.</value>
    public IEnumerable<MultiLevelHtmlTag> InnerTags
    {
        get
        {
            return new ReadOnlyCollection<MultiLevelHtmlTag>(this.innerTags);
        }
    }

    /// <summary>
    /// Adds the specified tag to the inner tag list.
    /// </summary>
    /// <param name="tag">The tag to add.</param>
    public void Add(MultiLevelHtmlTag tag)
    {
        if (tag == null)
        {
            throw new ArgumentNullException("tag");
        }

        this.innerTags.Add(tag);
    }

    /// <summary>
    /// Returns a <see cref="System.String"/> that represents this instance.
    /// </summary>
    /// <returns>
    /// A <see cref="System.String"/> that represents this instance.
    /// </returns>
    public override string ToString()
    {
        var sb = new StringBuilder();

        foreach (var tag in this.innerTags)
        {
            sb.Append(tag.ToString());
        }

        this.InnerHtml = sb.ToString();
        return base.ToString();
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ Great response; in my project I've just changed the inner tags to be TagBuilder (so that I can add "regular" TagBuilder objects to it); there's no actual need to have them as MultiLevelHtmlTags. \$\endgroup\$ Commented Jul 7, 2013 at 6:39
  • \$\begingroup\$ @ANeves - you need to use concat your results to the existing inner text or else you will end up with all empty tags. \$\endgroup\$ Commented Jun 12, 2014 at 21:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.