2009-01-25 14 views
8

Tôi đang cố gắng sử dụng System.Xml.Linq để tạo tài liệu XHTML. Như vậy, đại đa số các nút trong cây của tôi phải sử dụng namespace này:Cách tạo XElement với không gian tên mặc định cho trẻ em mà không sử dụng XNamespace trong tất cả các nút con

http://www.w3.org/1999/xhtml 

tôi có thể tạo XElement nút scoped tới namespace này một cách dễ dàng đủ, sử dụng một XNamespace, như thế này:

XNamespace xhtml = "http://www.w3.org/1999/xhtml"; 
// ... 
new XElement(xhtml + "html", // ... 

Tuy nhiên, tôi không muốn phải cung cấp XNamespace có sẵn trong tất cả các mã tạo nút HTML và phải đặt trước mỗi tên XElement (và XAttribute) duy nhất mà tôi tạo cho phù hợp.

Định dạng văn bản XML tự nó đưa ra yêu cầu này và cho phép đặt không gian tên mặc định trong tổ tiên được thừa kế bởi hậu duệ, sử dụng thuộc tính reserved xmlns. Tôi muốn làm điều gì đó tương tự bằng cách sử dụng System.Xml.Linq.

Điều này có khả thi không?

Trả lời

5

tôi đã quyết định sử dụng một lớp tĩnh gọi XHtml, trông như thế này:

public static class XHtml 
{ 
    static XHtml() 
    { 
     Namespace = "http://www.w3.org/1999/xhtml"; 
    } 

    public static XNamespace Namespace { get; private set; } 

    public static XElement Element(string name) 
    { 
     return new XElement(Namespace + name); 
    } 

    public static XElement Element(string name, params object[] content) 
    { 
     return new XElement(Namespace + name, content); 
    } 

    public static XElement Element(string name, object content) 
    { 
     return new XElement(Namespace + name, content); 
    } 

    public static XAttribute Attribute(string name, object value) 
    { 
     return new XAttribute(/* Namespace + */ name, value); 
    } 

    public static XText Text(string text) 
    { 
     return new XText(text); 
    } 

    public static XElement A(string url, params object[] content) 
    { 
     XElement result = Element("a", content); 
     result.Add(Attribute("href", url)); 
     return result; 
    } 
} 

này có vẻ là cách sạch của làm mọi thứ, đặc biệt khi tôi có thể thêm vào các thói quen tiện lợi, chẳng hạn như phương thức XHtml.A (không phải tất cả các lớp của tôi đều được hiển thị ở đây).

+0

Giải pháp này trông nặng và đáng sợ, nhưng nó thực sự đẹp, nhẹ, có thể mở rộng, làm cho mã của bạn ngắn hơn và bảo vệ chống lại lỗi chính tả trong tên phần tử hoặc thuộc tính. Wow! –

+0

Tôi chỉ hiểu tại sao nó có tất cả những ưu điểm này. Trong khi câu hỏi chỉ nói "Tôi muốn các không gian tên tự động", điều đơn giản và lành mạnh là "Tôi muốn một số phím tắt tiện lợi đóng gói một số kiến ​​thức cơ bản về HTML", trong đó hiệu ứng không gian tên chỉ là một sản phẩm phụ tốt. –

1

Vấn đề là XName được sử dụng để tạo ra các XElement cần phải xác định không gian tên chính xác. Những gì tôi sẽ bị cám dỗ để làm là tạo ra một lớp tĩnh như thế này: -

public static class XHtml 
{ 
    public static readonly XNamespace Namespace = "http://www.w3.org/1999/xhtml"; 
    public static XName Html { get { return Namespace + "html"; } } 
    public static XName Body { get { return Namespace + "body"; } } 
       //.. other element types 
} 

Bây giờ bạn có thể xây dựng một doc xhtml như thế này: -

XDocument doc = new XDocument(
    new XElement(XHtml.Html, 
     new XElement(XHtml.Body) 
    ) 
); 

Một cách tiếp cận khác cho rằng lớp học tĩnh sẽ : -

static class XHtml 
{ 
    public static readonly XNamespace Namespace = "http://www.w3.org/1999/xhtml"; 
    public static readonly XName Html = Namespace + "html"; 
    public static readonly XName Body = Namespace + "body"; 
} 

Điều này có nhược điểm là tất cả các XName có thể bất kể bạn sử dụng chúng nhưng lộn ngược là chuyển đổi Không gian tên + "thẻ tên" chỉ xảy ra một lần. Tôi không chắc chắn chuyển đổi này sẽ được tối ưu hóa nếu không. Tôi chắc chắn rằng XNames chỉ instanced một lần: -

XNamepace n = "http://www.w3.org/1999/xhtml"; 
XNames x = n + "A"; 
XName y = n + "A"; 
Object.ReferenceEquals(x, y) //is true. 
+0

Cách tiếp cận thứ ba là viết lại subtree, nút html xuống, trước khi thêm vào XDocument ở gốc. Tôi nhận thức được những cách khác để giải quyết vấn đề, tôi đã tự hỏi nếu có một cách xung quanh nó. Tôi đoán có lẽ là không. –

+0

Umm ... huh? nút html xuống? Tôi không hiểu. Bạn vẫn sẽ cần phải sử dụng XNames có không gian tên xhtml. – AnthonyWJones

+0

Anthony - viết lại cây để bao gồm không gian tên XHTML trong các tên không bị che khuất bởi một không gian tên, tức là kiểm tra XName.Namespace là XNamespace.None; bằng nút html, ý tôi là nút gốc của tài liệu XHTML. –

3

Tôi lấy đường dẫn viết lại đệ quy. Bạn không thực sự phải 'tái tạo lại' cái cây. Bạn chỉ có thể hoán đổi các tên nút (XName).

private static void ApplyNamespace(XElement parent, XNamespace nameSpace) 
    { 
     if(DetermineIfNameSpaceShouldBeApplied(parent, nameSpace)) 
     { 
      parent.Name = nameSpace + parent.Name.LocalName; 
     } 
     foreach (XElement child in parent.Elements()) 
     { 
      ApplyNamespace(child, nameSpace); 
     } 
    } 
Các vấn đề liên quan