Быстрый интерфейс для рендеринга HTML

=IF(DATEDIF(A1, B1, "D")>365, QUOTIENT(DATEDIF(A1, B1, "D"), 365)&" year(s) "&
                          QUOTIENT(MOD(DATEDIF(A1, B1, "D"), 365), 30)&" month(s) "&
                      MOD(QUOTIENT(MOD(DATEDIF(A1, B1, "D"), 365), 30), 30)&" day(s)",
 IF(DATEDIF(A1, B1, "D")>30,  QUOTIENT(DATEDIF(A1, B1, "D"), 30)&" month(s) "&
                                   MOD(DATEDIF(A1, B1, "D"), 30)&" day(s)", 
                                       DATEDIF(A1, B1, "D")&" day(s)"))

0

10
задан Patrik Hägne 5 January 2009 в 22:34
поделиться

4 ответа

Я вижу две проблемы:

  • Повторное использование тега (Tagname,…) . Почему бы не предложить методы расширения для каждого имени тега? По общему признанию, это раздувает интерфейс и довольно много пишет (=> генерация кода!).
  • Компилятор / IDE вам не помогает. В частности, он не проверяет отступы (он даже уничтожит его, когда вы сделаете отступ автоматически).

Обе проблемы могут быть решены с помощью лямбда-подхода:

writer.Write(body => new Tag[] {
    new Tag(h1 => "Hello, world!"),
    new Tag(p => "Indeed. What a lovely day.", new Attr[] {
        new Attr("style", "color: red")
    })
});

Это всего лишь один базовый подход. API, безусловно, потребуется гораздо больше работы. В частности, вложение одного и того же тега не будет работать из-за конфликтов имен аргументов. Кроме того, этот интерфейс не будет работать (или вообще) с VB. Но, к сожалению, то же самое относится и к другим современным API .NET, даже к интерфейсу PLINQ от Microsoft.

Другой подход, о котором я думал некоторое время назад, на самом деле пытается эмулировать Markaby, как код самбо. Основное отличие состоит в том, что я использую , используя блоки вместо foreach , таким образом, используя RAII:

using (var body = writer.body("xml:lang", "en")) {
    using (var h1 = body.h1())
        h1.AddText("Hello, World!");
    using (var p = body.p("style", "color: red"))
        p.AddText("Indeed. What a lovely day.");
}

Этот код не имеет проблем другого подхода. С другой стороны, он обеспечивает меньшую безопасность типов для атрибутов и менее элегантный интерфейс (для данного определения « элегантный »).

Я получаю оба кода для компиляции и даже создаю еще несколько или менее значимый вывод (т. е. HTML!).

у него нет проблем с другим подходом. С другой стороны, он обеспечивает меньшую безопасность типов для атрибутов и менее элегантный интерфейс (для данного определения « элегантный »).

Я получаю оба кода для компиляции и даже создаю еще несколько или менее значимый вывод (т. е. HTML!).

у него нет проблем с другим подходом. С другой стороны, он обеспечивает меньшую безопасность типов для атрибутов и менее элегантный интерфейс (для данного определения « элегантный »).

Я получаю оба кода для компиляции и даже создаю еще несколько или менее значимый вывод (т. е. HTML!).

3
ответ дан 4 December 2019 в 02:52
поделиться

Если вам нужно делать много такого рода вещей, рассматривали ли вы какой-нибудь шаблонизатор, такой как NHaml? 1287 В Ruby / Markaby это выглядело бы намного красивее.

    div :class=>"someClass someOtherClass" do 
        h1 "Lorem"
        select :id => "fooSelect", :name => "fooSelect", :class => "selectClass" do 
           option :title=>"selects the number 1", :value => 1 { "1" } 
           option :title=>"selects the number 2", :value => 2 { "2" } 
           option :title=>"selects the number 3", :value => 3 { "3" } 
        end
    end

Вы можете портировать аналогичный подход на .Net

    using(var d = HtmlTextWriter.Div.Class("hello"))
    {
        d.H1.InnerText("Lorem"); 
        using(var s = d.Select.Id("fooSelect").Name("fooSelect").Class("fooClass"))
        {
           s.Option.Title("select the number 1").Value("1").InnerText("1"); 
        }
    } 

Я думаю, что он читает вполне будет и поддерживает вложение.

РЕДАКТИРОВАТЬ Я украл использование у Конрада, потому что оно читается намного лучше.

У меня есть следующие проблемы с исходным предложением.

  1. Вы должны не забыть вызвать EndTag, в противном случае ваш HTML-код переходит на Foobar.
  2. Ваше пространство имен слишком загрязнено. HtmlTextWriterTag повторяется тонну раз, и его трудно расшифровать из-за накладных расходов.

Мой предложенный подход потенциально немного менее эффективен, но я думаю, что он решает эти проблемы и будет очень прост в использовании.

1
ответ дан 4 December 2019 в 02:52
поделиться

Это то, что я придумал, позаботившись о следующих соображениях:

  1. Я сохраняю часть ввода с помощью T.Tag после , используя T = HtmlTextWriterTag ; , что может вам понравиться или нет
  2. Я хотел получить хоть какую-то безопасность для последовательности цепочки вызовов ( Debug.Assert приведен только для краткости, намерение должно быть ясным)
  3. Я не хотел оборачивать мириады методов HtmlTextWriter.

     с помощью T = HtmlTextWriterTag;
    
    public class HtmlBuilder {
     Публичный делегат void Statement (HtmlTextWriter htmlTextWriter);
    
     public HtmlBuilder (HtmlTextWriter htmlTextWriter) {
     this.writer = htmlTextWriter;
     }
    // Начать оператор для тега; обязательный, 1-й оператор
     public HtmlBuilder B (оператор утверждения) {
     Debug.Assert (this.renderStatements.Count == 0);
     this.renderStatements.Add (инструкция);
     вернуть это;
     }
    // Операторы атрибутов для тега; необязательно, от 2-го до n-го операторов
     public HtmlBuilder A (оператор утверждения) {
     Debug.Assert (this.renderStatements.Count> 0);
     this.renderStatements.Insert (this.cntBeforeStatements ++, инструкция);
     вернуть это;
     }
    // Завершить оператор для тега; обязательное, последнее утверждение
     // нет возвращаемого значения, на этом блок должен остановиться
     public void E () {
     Debug.Assert (this.renderStatements.Count> 0);
     this.renderStatements.Add (i => {i.RenderEndTag ();});
     foreach (оператор renderStatement в this.renderStatements) {
     renderStatement (this.writer);
     }
    this.renderStatements.Clear (); this.cntBeforeStatements = 0;
     }
     частный int cntBeforeStatements = 0;
     закрытый только для чтения List  renderStatements = new List  ();
     частный писатель HtmlTextWriter только для чтения;
    }
    
    public class HtmlWriter {
     публичный делегат void BlockWithHtmlTextWriter (HtmlTextWriter htmlTextWriter);
     публичный делегат void BlockWithHtmlBuilder (HtmlBuilder htmlBuilder);
    
     общедоступная строка Render (блок BlockWithHtmlTextWriter) {
     StringBuilder stringBuilder = новый StringBuilder ();
     using (StringWriter stringWriter = new StringWriter (stringBuilder)) {
     using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter (stringWriter)) {
     блок (htmlTextWriter);
     }
     }
     вернуть stringBuilder.ToString ();
     }
     общедоступная строка Render (BlockWithHtmlBuilder block) {
     вернуть this.Render ((HtmlTextWriter htmlTextWriter) => 
     блок (новый HtmlBuilder (htmlTextWriter)));
     }
     // небольшой тест / образец
     static void Main (string [] args) {
     HtmlWriter htmlWriter = новый HtmlWriter ();
     System.Console.WriteLine (htmlWriter.Render ((HtmlBuilder b) => {
     bB (h => h.RenderBeginTag (T.Div))
     .A (h => h.AddAttribute ("foo", "bar"))
     .A (h => h.AddAttribute ("doh", "baz"))
     .E ();
     }));
     }
    }
    
0
ответ дан 4 December 2019 в 02:52
поделиться

Я хотел чтобы иметь такой синтаксис:

using (var w = new HtmlTextWriter(sw))
        {
            w.Html()
                .Head()
                    .Script()
                        .Attributes(new { type = "text/javascript", src = "somescript.cs" })
                        .WriteContent("var foo='bar'")
                    .EndTag()
                .EndTag()
                .Body()
                    .P()
                        .WriteContent("some content")
                    .EndTag()
                .EndTag()
            .EndTag();
        }

Чтобы добиться этого, я добавил методы расширения в HtmlTextWriter, хотя контейнер, вероятно, был бы более подходящим (меня больше интересовало, чтобы он работал в первую очередь!) Чувствуя себя ленивым, я не хотел писать метод для каждого из доступных тегов, поэтому я кодирую методы, используя шаблон t4, повторяя перечисление System.Web.UI.HtmlTextWriterTag. Атрибуты тегов управляются с помощью анонимных объектов; код в основном отражает анонимный тип, извлекает свойства и превращает их в атрибуты, которые, как мне кажется, придают результирующему синтаксису очень чистый вид.

Результат кодовой легенды:

using System;
using System.Web.UI;
using System.Collections.Generic;


/// <summary>
///  Extensions for HtmlTextWriter
/// </summary>
public static partial class HtmlWriterTextTagExtensions
{
    static Stack<Tag> tags = new Stack<Tag>();



        /// <summary>
        ///  Opens a Unknown Html tag
        /// </summary>
        public static HtmlTextWriter Unknown(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("Unknown",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a A Html tag
        /// </summary>
        public static HtmlTextWriter A(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("a",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Acronym Html tag
        /// </summary>
        public static HtmlTextWriter Acronym(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("acronym",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Address Html tag
        /// </summary>
        public static HtmlTextWriter Address(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("address",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Area Html tag
        /// </summary>
        public static HtmlTextWriter Area(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("area",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a B Html tag
        /// </summary>
        public static HtmlTextWriter B(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("b",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Base Html tag
        /// </summary>
        public static HtmlTextWriter Base(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("base",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Basefont Html tag
        /// </summary>
        public static HtmlTextWriter Basefont(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("basefont",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Bdo Html tag
        /// </summary>
        public static HtmlTextWriter Bdo(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("bdo",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Bgsound Html tag
        /// </summary>
        public static HtmlTextWriter Bgsound(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("bgsound",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Big Html tag
        /// </summary>
        public static HtmlTextWriter Big(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("big",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Blockquote Html tag
        /// </summary>
        public static HtmlTextWriter Blockquote(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("blockquote",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Body Html tag
        /// </summary>
        public static HtmlTextWriter Body(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("body",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Br Html tag
        /// </summary>
        public static HtmlTextWriter Br(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("br",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Button Html tag
        /// </summary>
        public static HtmlTextWriter Button(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("button",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Caption Html tag
        /// </summary>
        public static HtmlTextWriter Caption(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("caption",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Center Html tag
        /// </summary>
        public static HtmlTextWriter Center(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("center",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Cite Html tag
        /// </summary>
        public static HtmlTextWriter Cite(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("cite",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Code Html tag
        /// </summary>
        public static HtmlTextWriter Code(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("code",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Col Html tag
        /// </summary>
        public static HtmlTextWriter Col(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("col",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Colgroup Html tag
        /// </summary>
        public static HtmlTextWriter Colgroup(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("colgroup",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Dd Html tag
        /// </summary>
        public static HtmlTextWriter Dd(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("dd",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Del Html tag
        /// </summary>
        public static HtmlTextWriter Del(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("del",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Dfn Html tag
        /// </summary>
        public static HtmlTextWriter Dfn(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("dfn",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Dir Html tag
        /// </summary>
        public static HtmlTextWriter Dir(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("dir",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Div Html tag
        /// </summary>
        public static HtmlTextWriter Div(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("div",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Dl Html tag
        /// </summary>
        public static HtmlTextWriter Dl(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("dl",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Dt Html tag
        /// </summary>
        public static HtmlTextWriter Dt(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("dt",  null));
            return writer;
        }

        /// <summary>
        ///  Opens a Em Html tag
        /// </summary>
        public static HtmlTextWriter Em(this HtmlTextWriter writer)
        {
            WritePreceeding(writer);
            tags.Push(new Tag("em",  null));
            return writer;
        }
3
ответ дан 4 December 2019 в 02:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: