XDocument使用不同的本地名称重复命名空间
我有一个XML文档,如下所示:
我使用下面的代码来修改文档的Property Element:
XElement csdlEentity = csdlDoc.Root.Descendants() .Where(d => d.Name.LocalName == "EntityType") .FirstOrDefault(e => e.Attribute("Name").Value == "Customer"); var csdlProperty = csdlEentity.Descendants() .Where(d => d.Name.LocalName == "Property") .FirstOrDefault(e => e.Attribute("Name").Value == "Id"); XNamespace annotation = "https://schemas.microsoft.com/ado/2009/02/edm/annotation"; var attrib = new XAttribute(annotation + "StoreGeneratedPattern", "Computed"); csdlProperty.Add(attrib);
当我保存XDocument时,Property Element看起来像:
不过我想要的是:
问题是xmlns“ https://schemas.microsoft.com/ado/2009/02/edm/annotation ”在文档的根节点中被引用两次,带有两个不同的别名/ LocalNames(注释,p1)
xmlns:annotation="https://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns:p1="https://schemas.microsoft.com/ado/2009/02/edm/annotation"
我无法更改或篡改根节点。
如何保存文档或更新属性元素以提供所需的输出?
从理论上讲,使用前缀p1:StoreGeneratedPattern="Computed"
或annotation:StoreGeneratedPattern="Computed"
,因为这些意思完全相同 – 一个扩展的XML名称为{https://schemas.microsoft.com/ado/2009/02/edm/annotation}StoreGeneratedPattern
的元素{https://schemas.microsoft.com/ado/2009/02/edm/annotation}StoreGeneratedPattern
。 如果您的接收XML解析器(或QA部门?)在处理此问题时遇到问题,最简单的修复方法可能是修复解析器以符合标准 。
话虽这么说,从XElement
的引用源 ,事实certificate,命名空间/前缀属性对在写入时按照添加的顺序被推送到下推式堆栈 ,然后从上到下检查与元素命名空间的匹配。 stack – 以相反的顺序有效地进行匹配,其中添加了属性。 因此,如果您想使用前缀annotation
,则可以简单地置换根元素中重复名称空间的顺序。 (有关详细信息,请参阅此处 。)
但是,您写道,您无法更改或篡改根节点 。 因此,您将被迫做一些工作:您将需要创建自己的XmlWriter
包装器子类并自己重新映射前缀。
首先, XmlWriter
一个非抽象子类包装了一个“真正的” XmlWriter
:
public class XmlWriterProxy : XmlWriter { readonly XmlWriter baseWriter; public XmlWriterProxy(XmlWriter baseWriter) { if (baseWriter == null) throw new ArgumentNullException(); this.baseWriter = baseWriter; } protected virtual bool IsSuspended { get { return false; } } public override void Close() { baseWriter.Close(); } public override void Flush() { baseWriter.Flush(); } public override string LookupPrefix(string ns) { return baseWriter.LookupPrefix(ns); } public override void WriteBase64(byte[] buffer, int index, int count) { if (IsSuspended) return; baseWriter.WriteBase64(buffer, index, count); } public override void WriteCData(string text) { if (IsSuspended) return; baseWriter.WriteCData(text); } public override void WriteCharEntity(char ch) { if (IsSuspended) return; baseWriter.WriteCharEntity(ch); } public override void WriteChars(char[] buffer, int index, int count) { if (IsSuspended) return; baseWriter.WriteChars(buffer, index, count); } public override void WriteComment(string text) { if (IsSuspended) return; baseWriter.WriteComment(text); } public override void WriteDocType(string name, string pubid, string sysid, string subset) { if (IsSuspended) return; baseWriter.WriteDocType(name, pubid, sysid, subset); } public override void WriteEndAttribute() { if (IsSuspended) return; baseWriter.WriteEndAttribute(); } public override void WriteEndDocument() { if (IsSuspended) return; baseWriter.WriteEndDocument(); } public override void WriteEndElement() { if (IsSuspended) return; baseWriter.WriteEndElement(); } public override void WriteEntityRef(string name) { if (IsSuspended) return; baseWriter.WriteEntityRef(name); } public override void WriteFullEndElement() { if (IsSuspended) return; baseWriter.WriteFullEndElement(); } public override void WriteProcessingInstruction(string name, string text) { if (IsSuspended) return; baseWriter.WriteProcessingInstruction(name, text); } public override void WriteRaw(string data) { if (IsSuspended) return; baseWriter.WriteRaw(data); } public override void WriteRaw(char[] buffer, int index, int count) { if (IsSuspended) return; baseWriter.WriteRaw(buffer, index, count); } public override void WriteStartAttribute(string prefix, string localName, string ns) { if (IsSuspended) return; baseWriter.WriteStartAttribute(prefix, localName, ns); } public override void WriteStartDocument(bool standalone) { baseWriter.WriteStartDocument(standalone); } public override void WriteStartDocument() { baseWriter.WriteStartDocument(); } public override void WriteStartElement(string prefix, string localName, string ns) { if (IsSuspended) return; baseWriter.WriteStartElement(prefix, localName, ns); } public override WriteState WriteState { get { return baseWriter.WriteState; } } public override void WriteString(string text) { if (IsSuspended) return; baseWriter.WriteString(text); } public override void WriteSurrogateCharEntity(char lowChar, char highChar) { if (IsSuspended) return; baseWriter.WriteSurrogateCharEntity(lowChar, highChar); } public override void WriteWhitespace(string ws) { if (IsSuspended) return; baseWriter.WriteWhitespace(ws); } }
接下来,允许重新映射属性名称空间前缀的子类:
public class PrefixSelectingXmlWriterProxy : XmlWriterProxy { readonly Stack elements = new Stack (); readonly Func, string> attributePrefixMap; public PrefixSelectingXmlWriterProxy(XmlWriter baseWriter, Func, string> attributePrefixMap) : base(baseWriter) { if (attributePrefixMap == null) throw new NullReferenceException(); this.attributePrefixMap = attributePrefixMap; } public override void WriteStartAttribute(string prefix, string localName, string ns) { prefix = attributePrefixMap(prefix, localName, ns, elements); base.WriteStartAttribute(prefix, localName, ns); } public override void WriteStartElement(string prefix, string localName, string ns) { base.WriteStartElement(prefix, localName, ns); elements.Push(XName.Get(localName, ns)); } public override void WriteEndElement() { base.WriteEndElement(); elements.Pop(); // Pop after base.WriteEndElement() lets the base class throw an exception on a stack error. } }
最后你会用它像:
string xml; using (var sw = new StringWriter()) { using (var xmlWriter = XmlWriter.Create(sw, new XmlWriterSettings { Indent = true, IndentChars = " " })) using (var xmlWriterProxy = new PrefixSelectingXmlWriterProxy(xmlWriter, (string prefix, string localName, string ns, Stack parents) => { if (localName == "StoreGeneratedPattern" && ns == annotation && parents.Peek() == XName.Get("Property", "https://schemas.microsoft.com/ado/2009/11/edm")) return "annotation"; return prefix; }) ) { csdlDoc.WriteTo(xmlWriterProxy); } xml = sw.ToString(); } Debug.WriteLine(xml);
正如您所看到的,这只重新映射了属性前缀,但它可以通过重写WriteStartElement(string prefix, string localName, string ns
)显然可以扩展为重新映射元素前缀。
工作小提琴 。
我找到了解决方案,这完全归功于您的想法。 一般的想法是我将p1的值更改为添加了我的新属性的任何内容,然后在保存XDocument之前将p1返回到其原始值。
XAttribute p1 = csdlDoc.Root.Attributes() .First(a => a.IsNamespaceDeclaration && a.Name.LocalName == "p1"); p1.Value = "https://schemas.microsoft.com/ado/2009/02/edm/annotation/TEMP"; ...... // the same update now works as there is only one xmlns XNamespace annotation = "https://schemas.microsoft.com/ado/2009/02/edm/annotation"; var attrib = new XAttribute(annotation + "StoreGeneratedPattern", "Computed"); csdlProperty.Add(attrib); p1.Value = "https://schemas.microsoft.com/ado/2009/02/edm/annotation/";
另一个有效的解决方案是交换根节点上的顺序或声明(在注释之前声明p1),如下所示:
一般来说,两者看起来像廉价的解
上述就是C#学习教程:XDocument使用不同的本地名称重复命名空间分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1014481.html