C# 如何在不使用 XNamespace 的所有子节点中为子节点创建具有默认命名空间的 XElement

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/477962/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 04:56:58  来源:igfitidea点击:

How to create XElement with default namespace for children without using XNamespace in all child nodes

c#.netxmlnamespaceslinq-to-xml

提问by Barry Kelly

I'm trying to use System.Xml.Linqto create XHTML documents. Thus, the vast majority of the nodes in my trees ought to use this namespace:

我正在尝试使用System.Xml.Linq来创建 XHTML 文档。因此,我的树中的绝大多数节点都应该使用这个命名空间:

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

I can create XElementnodes scoped to this namespace easily enough, using an XNamespace, like this:

我可以XElement很容易地创建作用域到这个命名空间的节点,使用XNamespace,像这样:

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

However, I don't want to have to make an XNamespaceavailable throughout all the code that creates HTML nodes, and have to prefix every single XElement(and XAttribute) name I create accordingly.

但是,我不想让XNamespace所有创建 HTML 节点的代码都可用,并且必须相应地为我创建的每个XElement(和XAttribute)名称添加前缀。

The XML text format itself takes this requirement into account, and permits setting a default namespace in an ancestor which is inherited by descendants, using the reserved xmlnsattribute. I'd like to do something similar using System.Xml.Linq.

XML 文本格式本身考虑了这一要求,并允许使用保留xmlns属性在后代继承的祖先中设置默认名称空间。我想使用System.Xml.Linq.

Is this possible?

这可能吗?

采纳答案by Barry Kelly

I've decided to use a static class called XHtml, that looks like this:

我决定使用一个名为 的静态类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;
    }
}

This seems to be the cleanest way of doing things, particularly as I can then add in convenience routines, such as the XHtml.Amethod (not all of my class is shown here).

这似乎是最干净的做事方式,特别是因为我可以添加方便的例程,例如XHtml.A方法(此处未显示我的所有类)。

回答by AnthonyWJones

The problem is the the XName used to create the XElement needs to specify the correct namespace. What I would be tempted to do is create a static class like this:-

问题是用于创建 XElement 的 XName 需要指定正确的命名空间。我想做的是创建一个像这样的静态类:-

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
}

Now you can build a xhtml doc like this:-

现在您可以像这样构建一个 xhtml 文档:-

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

An alternative approach to that static class would be:-

该静态类的另一种方法是:-

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

This has the downside of instancing all the possible XName regardless of whether you use them but the upside is the conversion of Namespace + "tagname" only happens once. I'm not sure this conversion would be optimised out otherwise. I am sure that XNames are only instanced once:-

这具有实例化所有可能的 XName 的缺点,无论您是否使用它们,但优点是 Namespace + "tagname" 的转换只发生一次。我不确定这个转换是否会被优化掉。我确信 XNames 只实例化一次:-

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

回答by Julian Lettner

I took the recursively rewriting path. You do not really have to 'reconstruct' the tree. You can just swap out the node names (XName).

我采用了递归重写路径。您实际上不必“重建”树。您可以只换出节点名称 ( 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);
        }
    }