4

1: I have a .html file that has some markup with some placeholder tags.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
   First Name : <FIRSTNAME/>   <br />
   Last Name:  <LASTNAME/>
</body>
</html>

2: I have a Class to hold data returned from db

public class Person
{
    public Person()
    {
    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

3: PersonInfo.aspx I write out this .html with the placeholder replaced by actual values.

public partial class PersonInfo : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Person per= new Person();
        per.FirstName = "Hello";
        per.LastName = "World";

        string temp = File.ReadAllText(Server.MapPath("~/template.htm"));
        temp = temp.Replace("<FIRSTNAME/>", per.FirstName);
        temp = temp.Replace("<LASTNAME/>", per.LastName);
        Response.Write(temp);
    }
}

4: PersonInfo.aspx is literally empty since I am injecting html from code-behind.

When the PersonInfo.aspx is called the html-template markup with appropriate values in the placeholder will be displayed. Also there are chances I would like to send the final markup in an html email (though that is not part of the question as I know how to email).

Is this the best way to fill values in my html-template or is the any other better alternative?

Note: This is a very simple sample example. My class is very complex involving objects as properties and also my html template have 40-50 placeholders.

So code in my step 3 will need 40-50 Replace statements.

Feel free to ask if any doubts and really appreciate any inputs.

5
  • Can you explain a little more what end result you're looking for? Is this a dynamic web page someone is viewing in a browser or are you trying to generate email content? Commented Mar 6, 2011 at 18:07
  • Are you working with valid XML? Commented Mar 6, 2011 at 18:30
  • @Daniel, it could be both displayed on the page for user to print and if they opt can be emailed just by click of a button. Commented Mar 6, 2011 at 18:55
  • Are you completely bound to using webforms? This would be fairly easy to do using ASP.NET MVC and the Razor viewengine, and I'm 98% sure there's a way you can render it to get the end HTML content to send an email with too. Commented Mar 7, 2011 at 0:07
  • @Daniel: Yes, have to use webforms. Commented Mar 7, 2011 at 3:21

4 Answers 4

3

If your page is valid XML (as I'm guessing it is based on the example), then you could parse it into an XElement and do a descendant search by node name. You can probably write a more efficient version, but an example would be:

.NET 3.5

    public void Page_Load(object sender, EventArgs e)
    {
        Person person = new Person { FirstName = "Hello", LastName = "World" };
        var dictionary = typeof(Person).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .ToDictionary(p => p.Name.ToUpperInvariant(), p => (p.GetValue(person, null) ?? string.Empty).ToString());
        var xe = XElement.Parse(File.ReadAllText(HttpContext.Current.Server.MapPath("~/template.htm")));
        foreach (var key in dictionary.Keys)
        {
            foreach (var match in xe.Descendants(key))
            {
                match.ReplaceAll(dictionary[key]);
            }
        }
    }

.NET 2.0 Friendly:

        var person = new Person();
        person.FirstName = "Hello"; 
        person.LastName = "World";
        var dictionary = new Dictionary<string, string>();
        foreach(var propertyInfo in typeof(Person).GetProperties(BindingFlags.Public|BindingFlags.Instance))
        {
            var elementName = propertyInfo.Name.ToUpperInvariant();
            var value = (propertyInfo.GetValue(person, null) ?? string.Empty).ToString();
            dictionary.Add(elementName,value);
        }
        var xml = new XmlDocument();
        xml.LoadXml(File.ReadAllText(HttpContext.Current.Server.MapPath("~/template.htm")));
        foreach(var key in dictionary.Keys)
        {
            var matches = xml.GetElementsByTagName(key);
            for(int i = 0; i<matches.Count;i++)
            {
                var match = matches[i];
                var textNode = xml.CreateTextNode(dictionary[key]);
                match.ParentNode.ReplaceChild(textNode, match);
            }
        }
Sign up to request clarification or add additional context in comments.

4 Comments

XSLT also works like Avitus said, but it kind of depends on you knowing it, and probably will take more time than copying and pasting
I actually thought of using GetProperties using Reflection and get the PropertyInfo.Name and was able to retrieve the that. Is you code using Lambda Expression i.e. 3.0+ because I am using .NET 2.0. Though eventually, I might move to 4.0 but for now 2.0 is my framework. I will read more about XElement and see how it fits. Thanks for the code-snippet.
XElement is part of linq, so will not be available in .NET 2.0 either. You may want to consider switching to .NET 3.5 SP1, because it uses the same version of the CLR as .NET 2.0, and is easy to upgrade, but provides a whole lot of features
Thanks smartcaveman. I will definitly try it out. One potential issue I might see in using this approach is my properties should be named exactly the same as my placeholder or the other way around. Since this template is an existing one, I will have to check if I can modify it without impacting other part where it is being used.
1

I would change your page to use an xslt. This is a really easy way to do replacing of things from the database. The only work you'd have to do then is make your XML document with the data from your database.

2 Comments

I gave it a thought before that if I could go that route and so I am going to start scratching XSLT/XML surface too. But in that case the data should be in XML format right? Because my data is not just going to come from one class or query but I will need to make multiple DB calls to populate diffent placeholders in the template. Thanks for pitching your 2 cents.
This would be the way eventually I will be going but as of now am going am going to stick with the existing template.
1

I would use an SqlDataSource and a Repeater control. They make it very easy to pull your data from the database, and then display it on the page. You wouldn't need to do any code-behind as everything would be handled for you by .NET.

Your data source would look something like this:

<asp:sqlDataSource ID="mySqlDataSource" SelectCommand="SELECT firstName, lastName FROM tablename" />

And then you need a control that can use the returned data and display it on the page:

<asp:Repeater runat="server">
    <HeaderTemplate>
        <table>
    </HeaderTemplate>
    <ItemTemplate>
        <tr>
            <td>First Name: <%#Container.DataItem("firstName")%>"</td>
        </tr>
        <tr>
            <td>Last Name: <%#Container.DataItem("lastName")%></td>
        </tr>
    </ItemTemplate>
    <FooterTemplate>
        </table>
    </FooterTemplate>
</asp:Repeater>

Edit:

Since you don't want to use a datasource and a databound control, I would recommend the XmlTextWriter class. There is a very good tutorial here. This would allow you to be more flexible than if you were reading the template from a separate HTML file.

4 Comments

@FreeAslnBeer: Never thought of it but will have to see if it is going to be viable in my case. Thanks for the input.
I gave it a thought and seems this isn't going to be an option because first I don't need a repeating stuff and I can do the same in an .aspx markup as well. And also my data isn't tied to just one datasource but will have more than one sources.
@gbs: I still think my solution is perfectly valid. If you can explain a bit more about your data then I can tailor my response to your situation.
I am not saying it won't work, it will. I don't see a necessity of using Repeater or any DataBound Control in this case because then I can simply do that job in .aspx. I am not using SqlDataSources and have separate layer to do all DB work. I have four different stored procedures passing different parameters from different places and replace the placeholders with appropriate values. And I think I might need some calculations as well. So I am sure I wouldn't got the DataBoundControl route.
1

Since you are generating an email consider using MailDefinition.CreateMailMessage. You will have to copy the placeholders and replacement values to a Dictionary object.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.