How to change the XML namespace of a specific element

I have some xml set generated via xmlserialization of some WCF messages. Now I want to create a generic method in which I specify the xml file name and prefix, for example mailxml12 . Then, in the XML file, those elements that do not have any namespace prefix in their name should be replaced with mailxml12:

Like the source file:

 <DeliveryApptCreateRequest d2p1:ApptType="Pallet" d2p1:PickupOrDelivery="Delivery" d2p1:ShipperApptRequestID="4490660303D5" d2p1:SchedulerCRID="234234" xmlns:d2p1="http://idealliance.org/Specs/mailxml12.0a/mailxml_defs" xmlns="http://idealliance.org/Specs/mailxml12.0a/mailxml_tm"> <SubmittingParty d2p1:MailerID6="123446" d2p1:CRID="342343" d2p1:MaildatUserLicense="A123" /> <SubmittingSoftware d2p1:SoftwareName="asds" d2p1:Vendor="123" d2p1:Version="12" /> <SubmitterTrackingID>2CAD3F71B4405EB16392</SubmitterTrackingID> <DestinationEntry>No</DestinationEntry> <OneTimeAppt> <PreferredAppt>2012-06-29T09:00:00Z</PreferredAppt> </OneTimeAppt> <TrailerInfo> <Trailer> <TrailerNumber>A</TrailerNumber> <TrailerLength>20ft</TrailerLength> </Trailer> <Carrier> <CarrierName>N/A</CarrierName> <URL>http://test.com</URL> </Carrier> <BillOfLadingNumber>N/A</BillOfLadingNumber> </TrailerInfo> </DeliveryApptCreateRequest> 

After the desired method, you need to change it to the entire name of the element that does not have a prefix with mailxml: For example, DeliveryApptCreateRequest should become mailxml:DeliveryApptCreateRequest whereas an element of type d2p1:CompanyName should remain as it is.

I tried with the following code

  private void RepalceFile(string xmlfile) { XmlDocument doc = new XmlDocument(); doc.Load(xmlfile); var a = doc.CreateAttribute("xmlns:mailxml12tm"); a.Value = "http://idealliance.org/Specs/mailxml12.0a/mailxml_tm"; doc.DocumentElement.Attributes.Append(a); doc.DocumentElement.Prefix = "mailxml12tm"; foreach (XmlNode item in doc.SelectNodes("//*")) { if (item.Prefix.Length == 0) item.Prefix = "mailxml12tm"; } doc.Save(xmlfile); } 

the only problem with this is that the root element remains as it is, as long as everyone changes as necessary

+6
source share
3 answers

You can simply parse all XML as a string and insert namespaces where necessary. However, this solution can create many new lines used only in the algorithm, which is bad for performance. However, I wrote a function by parsing it this way, and it seems to run pretty quickly for the XML sample that you posted;). I can publish it if you want to use it.

Another solution is to load the XML as an XmlDocument and use the fact that it is a tree structure. This way you can create a method to recursively add the appropriate namespaces, where necessary. Unfortunately, the XmlNode.Name attribute is read-only and therefore you need to manually copy the entire xml structure to change the names of some nodes. I don’t have time to write code right now, so I’ll just let you write it. If you have any problems, just let me know.

Update

I checked your code and the code suggested by Jeff Mercado, and both of them seem to work correctly, at least in the XML example that you posted in the question. Make sure the XML you are trying to parse is the same as the one you published.

Just to make it work and solve the problem with the source space originally requested, you can use code that processes all the XML as String and parses it manually:

 private static String UpdateNodesWithDefaultNamespace(String xml, String defaultNamespace) { if (!String.IsNullOrEmpty(xml) && !String.IsNullOrEmpty(defaultNamespace)) { int currentIndex = 0; while (currentIndex != -1) { //find index of tag opening character int tagOpenIndex = xml.IndexOf('<', currentIndex); //no more tag openings are found if (tagOpenIndex == -1) { break; } //if it a closing tag if (xml[tagOpenIndex + 1] == '/') { currentIndex = tagOpenIndex + 1; } else { currentIndex = tagOpenIndex; } //find corresponding tag closing character int tagCloseIndex = xml.IndexOf('>', tagOpenIndex); if (tagCloseIndex <= tagOpenIndex) { throw new Exception("Invalid XML file."); } //look for a colon within currently processed tag String currentTagSubstring = xml.Substring(tagOpenIndex, tagCloseIndex - tagOpenIndex); int firstSpaceIndex = currentTagSubstring.IndexOf(' '); int nameSpaceColonIndex; //if space was found if (firstSpaceIndex != -1) { //look for namespace colon between tag open character and the first space character nameSpaceColonIndex = currentTagSubstring.IndexOf(':', 0, firstSpaceIndex); } else { //look for namespace colon between tag open character and tag close character nameSpaceColonIndex = currentTagSubstring.IndexOf(':'); } //if there is no namespace if (nameSpaceColonIndex == -1) { //insert namespace after tag opening characters '<' or '</' xml = xml.Insert(currentIndex + 1, String.Format("{0}:", defaultNamespace)); } //look for next tags after current tag closing character currentIndex = tagCloseIndex; } } return xml; } 

You can check this code to make the application work, however I highly recommend that you determine why the other proposed solutions did not help.

+2
source

Since you have a default namespace defined in this case, you can simply remove the default namespace declaration and add a new declaration for your new prefix using the old namespace name, effectively replacing it.

 var prefix = "mailxml"; var content = XElement.Parse(xmlStr); var defns = content.GetDefaultNamespace(); content.Attribute("xmlns").Remove(); content.Add(new XAttribute(XNamespace.Xmlns + prefix, defns.NamespaceName)); 
+1
source
Decision

@JeffMercado does not work for me (maybe because I did not have a default namespace).

I ended up using:

 XNamespace ns = Constants.Namespace; el.Name = (ns + el.Name.LocalName) as XName; 

To change the namespace for the entire document, I used:

 private void rewriteNamespace(XElement el) { // Change namespace XNamespace ns = Constants.Namespace; el.Name = (ns + el.Name.LocalName) as XName; if (!el.HasElements) return; foreach (XElement d in el.Elements()) rewriteNamespace(d); } 

Using:

 var doc = XDocument.parse(xmlStr); rewriteNamespace(doc.Root) 

NTN

0
source

Source: https://habr.com/ru/post/918483/


All Articles