cgicc: многоуровневый элемент - PullRequest
1 голос
/ 31 октября 2011

Я начинаю с cgicc, который позволяет мне сохранять код коротким и чистым. Но сейчас я борюсь. Я хочу что-то подобное:

<ul>
  <li>
    <a href="#" ><span>Main 1</span></a>
    <ul>
      <li><a href="ref1-1" ><span>Sub 1</span></a></li>
      <li><a href="ref1-2" ><span>Sub 2</span></a></li>
      <li><a href="ref1-3" ><span>Sub 3</span></a></li>
    </ul>
  </li>
  <li>
    <a href="#" ><span>Main 2</span></a>
    <ul>
      <li><a href="ref2-1" ><span>Sub 1</span></a></li>
      <li><a href="ref2-2" ><span>Sub 2</span></a></li>
      <li><a href="ref2-3" ><span>Sub 3</span></a></li>
    </ul>
  </li>
</ul>

Внутренние блоки очень большие, поэтому я не хочу объединять вызовы. Моя первая попытка, подобная этой (надеюсь, я хорошо ее кодировал):

cout << ul() << endl;
  cout << li() << endl;
    cout << a("Main 1").set("href", "#") << endl;
    cout << ul() << endl; // <-- must fail here!
      cout << li(a("Sub 1").set("href", "ref1-1")) << endl;
      cout << li(a("Sub 2").set("href", "ref1-2")) << endl;
      cout << li(a("Sub 3").set("href", "ref1-3")) << endl;
    cout << ul() << endl;
  cout << li() << endl;
  cout << li() << endl;
    cout << a("Main 2").set("href", "#") << endl;
    cout << ul() << endl;
      cout << li(a("Sub 1").set("href", "ref2-1")) << endl;
      cout << li(a("Sub 2").set("href", "ref2-2")) << endl;
      cout << li(a("Sub 3").set("href", "ref2-3")) << endl;
    cout << ul() << endl;
  cout << li() << endl;
cout << ul() << endl;

Проблема в булевом состоянии для таких элементов, как

  • и т. Д. Итак, есть ли лучшая практика и разумное решение для этого? - Анди

    РЕДАКТИРОВАТЬ: мое новое решение: дополнительные элементы класса "простой":

    #include <cgicc/HTMLElement.h>
    #include <cgicc/HTMLAttributeList.h>
    
    template<class Tag>
    class HTMLSimpleElement : public cgicc::HTMLElement
    {
    public:
      HTMLSimpleElement() : HTMLElement(0, 0, 0, EElementType(-1))
      {}
    
      HTMLSimpleElement(const cgicc::HTMLAttributeList& attributes) : HTMLElement(&attributes, 0, 0, EElementType(-1))
      {}
    
      virtual ~HTMLSimpleElement() {}
    
      virtual inline HTMLElement* clone() const
      { return new HTMLSimpleElement<Tag>(*this); }
    
      virtual inline const char* getName() const
      { return Tag::getName(); }
    
      virtual void render(std::ostream& out) const
      {
        const cgicc::HTMLAttributeList* attributes = getAttributes();
    
        out << '<' << getName();
    
        if (attributes != NULL)
        {
          out << ' ';
          attributes->render(out);
        }
    
        out << ">";
      }
    };
    
    #define TAG(name, tag) \
    class name##Tag   \
    { public: inline static const char* getName() { return tag; } }
    
    #define SIMPLE_ELEMENT(name, tag) \
    TAG(name, tag); typedef HTMLSimpleElement<name##Tag> name
    
    SIMPLE_ELEMENT (divB, "div");
    SIMPLE_ELEMENT (divE, "/div");
    
    // and so on... 
    

    Таким образом, я могу использовать функции-члены и иметь полный контроль над тегами BEGIN и END. Кто-нибудь другой, более разумное решение?

1 Ответ

2 голосов
/ 05 апреля 2013

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

Ваш второй кодовый блок неверен.Когда вы указываете тег с помощью cgicc, он выводит весь тег, включая включенные дочерние элементы.Без охвативших детей государство запоминается и меняется местами с каждой конструкцией.Это означает, что для их объединения вы, вероятно, должны использовать объекты, которые вы собираете в виде дерева.Для упрощенного примера возьмем этот сокращенный желаемый результат:

<ul>
  <li>
    <a href="#" ><span>Main 1</span></a>
    <ul>
      <li><a href="ref1-1" ><span>Sub 1</span></a></li>
      <li><a href="ref1-2" ><span>Sub 2</span></a></li>
      <li><a href="ref1-3" ><span>Sub 3</span></a></li>
    </ul>
  </li>
</ul>

Если вы попробуете код cgicc как такой:

cout << ul() << endl;
  cout << li() << endl;
    cout << a("Main 1").set("href", "#") << endl;
    cout << ul() << endl; // <-- must fail here!
      cout << li(a("Sub 1").set("href", "ref1-1")) << endl;
      cout << li(a("Sub 2").set("href", "ref1-2")) << endl;
      cout << li(a("Sub 3").set("href", "ref1-3")) << endl;
    cout << ul() << endl;
  cout << li() << endl;
cout << ul() << endl;

Вы получите этот беспорядок, который не является правильным html:

<ul>
<li>
<a href="#" >Main 1</a>
</ul>
<li><a href="ref1-1" >Sub 1</a></li>
<li><a href="ref1-2" >Sub 2</a></li>
<li><a href="ref1-3" >Sub 3</a></li>
<ul>
</li>
</ul>

Вероятно, вы должны обрабатывать это более объектно-ориентированным образом, отслеживая объекты, которые вы используете для создания своей страницы, например так (указатели будут отслеживать вновь добавленных дочерних элементов и будут избегатьсоздание ненужных копий; без указателей необходимо обязательно добавлять теги в правильном порядке):

ul* outerList = new ul();
li* outerItem = new li();
ul* innerList = new ul();

outerList->add(outerItem);
outerItem->add(a(span("Main 1")).set("href", "#"));
outerItem->add(innerList);
innerList->add(li(a(span("Sub 1")).set("href", "ref1-1")));
innerList->add(li(a(span("Sub 2")).set("href", "ref1-2")));
innerList->add(li(a(span("Sub 3")).set("href", "ref1-3")));

cout << *outerList << endl;

Вы также можете создавать их на лету, используя конструкторы и методы добавления и установки:

cout << ul(li().add(a(span("Main 1")).set("href", "#")).add(ul().add(li(a(span("Sub 1")).set("href", "ref1-1"))).add(li(a(span("Sub 2")).set("href", "ref1-2"))).add(li(a(span("Sub 3")).set("href", "ref1-3"))))) << endl;

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

Думайте о HTML как об иерархии.Мне всегда было лучше просто использовать XHTML с libxml.

...