[英]How to set the default XML namespace for an XDocument
如何設置現有 XDocument 的默認命名空間(以便我可以使用 DataContractSerializer 對其進行反序列化)。 我嘗試了以下方法:
var doc = XDocument.Parse("<widget/>");
var attrib = new XAttribute("xmlns",
"http://schemas.datacontract.org/2004/07/Widgets");
doc.Root.Add(attrib);
我得到的例外是The prefix '' cannot be redefined from '' to 'http://schemas.datacontract.org/2004/07/Widgets' within the same start element tag.
有任何想法嗎?
不確定這是否已經在 .net 3.5 或僅在 4 中有效,但這對我來說很好用:
XNamespace ns = @"http://mynamespace";
var result = new XDocument(
new XElement(ns + "rootNode",
new XElement(ns + "child",
new XText("Hello World!")
)
)
);
產生這個文件:
<rootNode xmlns="http://mynamespace">
<child>Hello World!</child>
</rootNode>
重要的是始終使用ns + "NodeName"
語法。
Linq to XML 似乎沒有為此用例提供 API(免責聲明:我沒有深入研究)。 如果更改根元素的命名空間,如下所示:
XNamespace xmlns = "http://schemas.datacontract.org/2004/07/Widgets";
doc.Root.Name = xmlns + doc.Root.Name.LocalName;
只有根元素的命名空間會發生變化。 所有孩子都將有一個明確的空 xmlns 標簽。
解決方案可能是這樣的:
public static void SetDefaultXmlNamespace(this XElement xelem, XNamespace xmlns)
{
if(xelem.Name.NamespaceName == string.Empty)
xelem.Name = xmlns + xelem.Name.LocalName;
foreach(var e in xelem.Elements())
e.SetDefaultXmlNamespace(xmlns);
}
// ...
doc.Root.SetDefaultXmlNamespace("http://schemas.datacontract.org/2004/07/Widgets");
或者,如果您更喜歡不改變現有文檔的版本:
public XElement WithDefaultXmlNamespace(this XElement xelem, XNamespace xmlns)
{
XName name;
if(xelem.Name.NamespaceName == string.Empty)
name = xmlns + xelem.Name.LocalName;
else
name = xelem.Name;
return new XElement(name,
from e in xelem.Elements()
select e.WithDefaultXmlNamespace(xmlns));
}
我有同樣的要求,但我想出了一些細微的不同:
/// <summary>
/// Sets the default XML namespace of this System.Xml.Linq.XElement
/// and all its descendants
/// </summary>
public static void SetDefaultNamespace(this XElement element, XNamespace newXmlns)
{
var currentXmlns = element.GetDefaultNamespace();
if (currentXmlns == newXmlns)
return;
foreach (var descendant in element.DescendantsAndSelf()
.Where(e => e.Name.Namespace == currentXmlns)) //!important
{
descendant.Name = newXmlns.GetName(descendant.Name.LocalName);
}
}
如果你想正確地做到這一點,你必須考慮,你的元素可能包含不同命名空間的擴展元素。 您不想全部更改它們,而只想更改那些默認命名空間元素。
R. Martinho Fernandes 上面的回答,(不會改變現有文檔)只需要一個小的調整,以便也返回元素值。 我沒有在 angst 中測試過這個,只是在玩 linqpad,抱歉沒有提供單元測試。
public static XElement SetNamespace(this XElement src, XNamespace ns)
{
var name = src.isEmptyNamespace() ? ns + src.Name.LocalName : src.Name;
var element = new XElement(name, src.Attributes(),
from e in src.Elements() select e.SetNamespace(ns));
if (!src.HasElements) element.Value = src.Value;
return element;
}
public static bool isEmptyNamespace(this XElement src)
{
return (string.IsNullOrEmpty(src.Name.NamespaceName));
}
修改擴展方法以包含 XElement.Value(即葉節點):
public static XElement WithDefaultXmlNamespace(this XElement xelem, XNamespace xmlns)
{
XName name;
if (xelem.Name.NamespaceName == string.Empty)
name = xmlns + xelem.Name.LocalName;
else
name = xelem.Name;
if (xelem.Elements().Count() == 0)
{
return new XElement(name, xelem.Value);
}
return new XElement(name,
from e in xelem.Elements()
select e.WithDefaultXmlNamespace(xmlns));
}
現在它對我有用!
不要忘記還復制剩余的屬性:
public static XElement WithDefaultXmlNamespace(this XElement xelem, XNamespace xmlns)
{
XName name;
if (xelem.Name.NamespaceName == string.Empty)
name = xmlns + xelem.Name.LocalName;
else
name = xelem.Name;
XElement retelement;
if (!xelem.Elements().Any())
{
retelement = new XElement(name, xelem.Value);
}
else
retelement= new XElement(name,
from e in xelem.Elements()
select e.WithDefaultXmlNamespace(xmlns));
foreach (var at in xelem.Attributes())
{
retelement.Add(at);
}
return retelement;
}
如果您知道所有元素都將使用相同的命名空間。 例如,如果您正在生成一個 SVG 文檔,那么您可以創建一個從XElement
繼承的元素並在構造函數中顯式設置xlmns
命名空間。
using System.Xml.Linq;
namespace SVG
{
public class SvgElement : XElement
{
private static readonly XNamespace xmlns = "http://www.w3.org/2000/svg";
/// <inheritdoc />
public SvgElement(string name) : base(new XElement(xmlns + name))
{
}
/// <inheritdoc />
public SvgElement(string name, object content) : this(name)
{
this.Add(content);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.