Как создать 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-узлы, и должен префикс каждый XElement
(и XAttribute
) имя, которое я создаю соответственно.
текстовый формат 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.