2011-03-02 5 views
1

현재 문서를 나타내는 클래스가 있습니다. 이 문서는 HTML로 표시되어야합니다. GetHTML()과 같은 메서드를 호출하여 렌더링해야 할 문서의 속성/섹션에 GetHTML()을 호출하고 싶습니다. 나는 처음에 linq와 XElement을 사용하려고했지만, HTML의 특정 태그에 문제가 발생할 수 있는지 궁금합니다. HtmlTextWriter을 사용하면 더 좋습니다. 이 상황에 대한 제안이나 최선의 실천에 대해 공개적입니다. 감사!클래스와 그 속성을 나타내는 HTML을 어떻게 생성해야합니까?

답변

2

HTML로 렌더링 할 수있는 데이터 모델을 가지고 있으며 컴포지션에 충실도가 있는지, 그리고 재귀 적으로 하위 개체를 검색하고 렌더링 할 수 있는지 생각하고 있다고 생각합니다.

"클래식"ASP.net은 렌더링 모델에서이 모든 작업이 모든 것이 컨트롤이고 각 컨트롤에 Render (HtmlTextWriter) 메서드가있는 방법을 사용합니다. 자식 컨트롤 (복합 컨트롤, 사용자 컨트롤, 페이지 등)을 포함하는 컨트롤에는 자체 컨텍스트 내에서 자식 컨트롤 각각을 재귀 적으로 렌더링하는 논리가 있습니다. 예 : 복합 컨트롤의 Render 메서드는 RenderBeginTag를 호출 한 다음 RenderChildren을 호출 한 다음 RenderEndTag를 호출하고 전체 Response를 렌더링하는 데 사용되는 것과 동일한 HtmlTextWriter에 대한 참조를 전달합니다. 페이지 및 사용자 정의 컨트롤과 같은 요소는 템플릿 (aspx)도 구문 분석하기 때문에 조금 더 복잡해 지지만 하루가 끝날 때 해당 템플릿은 Render 메서드의 처방에 지나지 않습니다.

글쎄,이 문제는 그것이 우려를 분리하는 관점에서 짜증이다. 데이터 문서가 HTML로 렌더링하기 위해 모든 코드를 포함해야하는 이유는 무엇입니까? 또한 GetHtml()의 아이디어가 마음에 들지 않습니다. 왜냐하면 여러분이 이미 발명 된 것을 재발 명할 것임을 암시하기 때문입니다. 여기에 MVC ViewEngine을 재사용하는 것은 좋은 생각 일 수 있습니다. HtmlTextWriter와 비교하여 개발할 수있는 기능이 많이 있으며 쉽게 개발할 수 있습니다.

아무튼. 내 제안은 귀하의 문서 클래스에 대한 새로운 인터페이스를 만드는 것입니다; "iRenderable"이라고 부르 자.이 인터페이스에 대한 하나의 요구 사항은 "ViewName"이라는 문자열이다.

문서 (모델)를 HTML로 변환하려면 RenderPartial (model.ViewName, model)을 호출하면됩니다. 그런 다음 해당 문서에 iRenderable 자식 요소가있는 경우 (해당 뷰 내에서) RenderPartial (model.SomeChild.ViewName, model.SomeChild)을 다시 호출합니다.

여기 있습니다. MVC는 템플릿과 무언가로 무거운 짐을 덜어줍니다. 그리고 여러분은 여러분의 데이터 모델에 수많은 절차 적 렌더링 쓰레기를 굽히지 않습니다.

interface IRenderable 
{ 
    string ViewName 
    { 
     get; 
    } 
} 

public class Table : IRenderable 
{ 
    public string ViewName 
    { 
     get 
     { 
      return "Table"; 
     } 
    } 

    public List<Row> Rows { get; set; } 
} 

public class Row : IRenderable 
{ 
    public string ViewName 
    { 
     get 
     { 
      return "Row"; 
     } 
    } 

    public string Value { get; set; } 
} 

행이 테이블에있는 경우 인터페이스에 신경을 쓰지 않는 이유는 무엇입니까? 어쩌면 당신이 렌더링하고자하는 객체 (또는 객체들의 집합)가 있고 그 부모 뷰가 그 타입에 대해 알지 못하는 경우가있을 수 있기 때문입니다. IRenderable에 캐스트하려고 시도해도 오브젝트를 렌더링 할 수 있습니다.

+0

일부 코드 예제 (간략하지만)가 도움이 될 것입니다. –

1

DOM을 직접 만든 경우 방문자 패턴을 조사 할 수 있습니다. DOM 자체에서 HTML 문서를 만드는 데 필요한 특정 코드를 사용하는 것을 피할 수 있습니다. 나는 이전과 동일한 작업을 수행했지만 DOM 클래스에 새로운 기능을 추가하는 새로운 방법을 계속 찾습니다. 이것은 당신이 내가 제공 한 5 개 기본 클래스에서 파생 더 요소를 추가해야합니다 기본 문서 구조를 줄 것이다

interface IVisitable { 
    void Assign(IVisitor); 
} 

interface IVisitor { 
    void Visit(Document document); 
    void Visit(Section section); 
    void Visit(Paragraph paragraph); 
} 

class Element : IVisitable { 
    void IVisitable.Assign(IVisitor visitor) { 
     this.Assign(visitor); 
    } 
    protected abstract void Assign(IVisitor visitor); 
} 

abstract class Block : Element { } 
abstract class Inline : Element { } 
abstract class BlockContainer<TElement> : Block, ICollection<TElement> { } 
abstract class ElementContainer<TElement> : Element, ICollection<TElement> { } 
abstract class InlineContainer<TElement> : Inline, ICollection<TElement> { } 

class Paragraph : BlockContainer<Inline> { 
    protected override void Assign(IVisitor visitor) { visitor.Visit(this); } 
} 

class Section : BlockContainer<Block> { 
    public string Title { get; set; } 
    protected override void Assign(IVisitor visitor) { visitor.Visit(this); } 
} 

class Document : ElementContainer<Block> { 
    protected override void Assign(IVisitor visitor) { visitor.Visit(this); } 
} 

: 다음은 몇 가지 예입니다. 방문자 패턴은 IVisitor 인터페이스가 구현 된 모든 "방문 가능한"요소를 알고 있다는 사실에 크게 의존합니다.광산이 Document, SectionParagraph 클래스에 대해 알 필요가 있음을 알 수 있듯이 (실제로 추측 할 수 있듯이 실제 사례에서는 훨씬 더 많은 것을 포함합니다).

너무 렌더링해야합니다 귀하의 요소가 여러 차일이있는 부분에 대해서는

, 나는이 방문자 구현 만들었습니다

abstract class Visitor : IVisitor { 
    public virtual void Visit(Document document) { 
     ICollection<Block> container = document; // I dont like to use the 'as' keyword, if I only want to fool the compiler to pick another overload. 
     this.Visit(container); 
    } 
    public virtual void Visit(Section section) { 
     ICollection<Block> container = section; 
     this.Visit(container); 
    } 
    public virtual void Visit(Paragraph paragraph) { 
     ICollection<Inline> container = paragraph; 
     this.Visit(container); 
    } 
    protected virtual void Visit(ICollection<Inline> container) { } 
    protected virtual void Visit(ICollection<Block> container) { } 
    protected virtual void Visit(ICollection<Element> container) { } 
} 

이 하나가 당신에게 당신은 이러한 요소를 무시할 수 있습니다 구현을 제공합니다 당신 이 메소드 중 하나를 무시하지 않으면보다 일반적인 방문 메소드가 도입되어 요소의 ICollection 부분 만 대상으로합니다 (이전에 말한 것처럼 Visitor 패턴은 방문 요소에 대해 모두 알아야합니다).

이 구현 몇 가지 깊이 우선 검색 동작을 만들려면이 다른 방문자가 도입됩니다 : 당신이 당신의 "문서"에서 HTML을 생성 할 경우

abstract class SearchVisitor : Visitor { 
    protected override Visit(ICollection<Block> container) { 
     this.AssignAll(container); 
    } 
    protected override Visit(ICollection<Inline> container) { 
     this.AssignAll(container); 
    } 
    protected override Visit(ICollection<Element> container) { 
     this.AssignAll(container); 
    } 
    private void AssignAll<TElement>(IEnumerable<TElement> container) { 
     foreach (IVisitable element in container) { 
      element.Assign(this); 
     } 
    } 
} 

, 당신은 다음 그냥이 목적을 위해 SearchVisitor을 구현할 수 있습니다 :

class HtmlMarkupRenderer : SearchVisitor { 
    private readonly XmlWriter writer; 
    private int sectionDepth = 0; 
    public HtmlMarkupRenderer(TextWriter textWriter) { 
     this.writer = XmlWriter.Create(textWriter, new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Fragment }); 

    public override void Visit(Section section) { 
     this.sectionDepth++; 
     string headingElement = String.Concat("h", Math.Max(this.sectionDepth, 6)); 
     this.writer.WriteElementString(headingElement, section.Title); 
     // The base implementation will assign this visitor to all childs of section. 
     base.Visit(section); 
     this.sectionDepth--; 
    } 

    public override void Visit(Paragraph paragraph) { 
     this.writer.WriteStartElement("p"); 
     base.Visit(paragraph); 
     this.writer.WriteEndElement(); 
    } 
} 

나는이 "레이아웃"에 많은 시간을 할애하여 매우 빨리 재현 할 수 있지만 약간의 오버 헤드가 발생할 수 있습니다. 이 점에 대해 더 자세히 알고 싶다면 알려주세요.

관련 문제