Как создать XElement с пространством имен по умолчанию для детей без использования XNamespace во всех дочерних узлах

Я пытаюсь использовать System.Xml.Linq для создания документов XHTML. Таким образом, подавляющее большинство узлов в моих деревьях должны использовать это пространство имен:

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

я могу создать XElement узлы достаточно легко доступны для этого пространства имен, используя XNamespace, например:

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

тем не менее, я не хочу, чтобы сделать XNamespace доступен во всем коде, который создает HTML-узлы, и должен префикс каждый XElementXAttribute) имя, которое я создаю соответственно.

текстовый формат XML сам учитывает это требование и разрешает установку пространства имен по умолчанию в предке, который наследуется потомками, используя зарезервированное . Я хотел бы сделать что-то подобное, используя System.Xml.Linq.

возможно ли это?

3 ответов


я решил использовать статический класс, называемый XHtml, который выглядит так:

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;
    }
}

это, кажется, самый чистый способ делать вещи, особенно, как я могу затем добавить в удобных процедур, таких как XHtml.A метод (не весь мой класс показан здесь).


Я выбрал рекурсивный путь перезаписи. На самом деле вам не нужно "реконструировать" дерево. Вы можете просто поменять местами имена узлов (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);
        }
    }

проблема заключается в том, что XName, используемый для создания XElement, должен указать правильное пространство имен. То, что я хотел бы сделать, это создать статический класс, как это: -

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
}

теперь вы можете создать документ xhtml, как это: -

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

альтернативным подходом к этому статическому классу было бы: -

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";
}

это имеет обратную сторону создания всех возможных XName независимо от того, используете ли вы их, но вверх-это преобразование пространства имен + "tagname" случается только один раз. Я не уверен, что это преобразование будет оптимизировано в противном случае. Я уверен, что XNames создаются только один раз: -

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