c# - XDocument duplicate namespace with different Local Name -


i have xml document looks this:

    <schema namespace="bbsf_model" alias="self"       p1:usestrongspatialtypes="false"       xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation"       xmlns:p1="http://schemas.microsoft.com/ado/2009/02/edm/annotation"       xmlns="http://schemas.microsoft.com/ado/2009/11/edm">     <entitytype name="customer">         <property name="id" type="guid" nullable="false" />     </entitytype>   </schema> 

i used below code modify property element of document:

    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 = "http://schemas.microsoft.com/ado/2009/02/edm/annotation";     var attrib = new xattribute(annotation + "storegeneratedpattern", "computed");     csdlproperty.add(attrib); 

when save xdocument property element looks like:

    <property name="id" type="guid" nullable="false" p1:storegeneratedpattern="computed" /> 

however want is:

  <property name="id" type="guid" nullable="false" annotation:storegeneratedpattern="computed" /> 

the problem xmlns "http://schemas.microsoft.com/ado/2009/02/edm/annotation" referenced twice in root node of document 2 different aliases/localnames (annotation, p1)

    xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation"     xmlns:p1="http://schemas.microsoft.com/ado/2009/02/edm/annotation" 

i cannot change or tamper root node.

how can save document or update property element give required output?

in theory, shouldn't matter whether use prefix p1:storegeneratedpattern="computed" or annotation:storegeneratedpattern="computed", since these mean exactly same thing -- element expanded xml name of {http://schemas.microsoft.com/ado/2009/02/edm/annotation}storegeneratedpattern. if receiving xml parser (or qa department?) has problem dealing this, easiest fix may fix parser conform standard.

that being said, reference source xelement, turns out namespace/prefix attribute pairs pushed onto push-down stack in order of addition while writing, checked matches against element namespace top bottom of stack -- doing match in reverse order in attributes added. if wanted use prefix annotation, permute order of duplicated namespaces in root element. (for details, see here.)

but, wrote cannot change or tamper root node. thus, you're going forced bit of work: you're going need create own wrapper subclass of xmlwriter , prefix remapping yourself.

first, non-abstract subclass of xmlwriter wraps "real" 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 { { 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     {         { 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);     } } 

next, subclass allows attribute namespace prefixes remapped:

public class prefixselectingxmlwriterproxy : xmlwriterproxy {     readonly stack<xname> elements = new stack<xname>();     readonly func<string, string, string, stack<xname>, string> attributeprefixmap;      public prefixselectingxmlwriterproxy(xmlwriter basewriter, func<string, string, string, stack<xname>, 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 base class throw exception on stack error.     } } 

then use like:

        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<xname> parents) =>                 {                     if (localname == "storegeneratedpattern" && ns == annotation && parents.peek() == xname.get("property", "http://schemas.microsoft.com/ado/2009/11/edm"))                         return "annotation";                     return prefix;                 })                 )             {                 csdldoc.writeto(xmlwriterproxy);             }             xml = sw.tostring();         }         debug.writeline(xml); 

as can see remaps attribute prefixes, extended remap element prefixes overriding writestartelement(string prefix, string localname, string ns).

working fiddle.


Comments

Popular posts from this blog

c# - Binding a comma separated list to a List<int> in asp.net web api -

Delphi 7 and decode UTF-8 base64 -

html - Is there any way to exclude a single element from the style? (Bootstrap) -