Removing whitespace in self-closing node and keeping UTF-8 hex entity values intact? I work with some xml files which have UTF-8 characters like &amp;#x00A9;, &amp;#x00EB; but they are converted to their image counterparts i.e. ©, ë, whenever I use XDocument to modify the file and also the self-closing nodes e.x. &lt;a type="box"/&gt; become &lt;a type="box" /&gt; i.e. an extra whitespace is added to the node, but I want to keep the entities like &#x00A9;, &#x00EB; etc as it is and also remove the extra whitespace in the self-closing nodes.

Currently I'm doing it in below fashion (sample example code)

var path = @"C:\Users\Temp\sample.xml";
var content=File.ReadAllText(path);
//replace all "&amp;" with "&amp;amp;" to prevent conversion of entity
var newcontent=content.Replace("&amp;", "&amp;amp;");
File.WriteAllText(path,newcontent);
XDocument doc = XDocument.Load(path, LoadOptions.PreserveWhitespace);
string _count = doc.Descendants("fig").Count().ToString();
doc.Descendants("fig-count").First().Value = _count;
doc.Save(path, SaveOptions.DisableFormatting);
//replace all "&amp;amp" with "&amp;" to go back to the original state and also replace all whitespace
//in the self-closing nodes after the XDocument process complets
var x=File.ReadAllText(path);
var y=x.Replace(" /&gt;", "/&gt;");
File.WriteAllText(path,y.Replace("&amp;amp;", "&amp;"));


Can anyone show me a more efficient way of doing this?
You can do something like this (using your previously posted question code as demo)

Regex regex = new Regex(@"(?&lt;=\\tag\s?\{)[^\}]+(?=\})");
string xml = escape_string(File.ReadAllText(@"C:\Users\Temp\Desktop\test.xml"), 0);
var xdoc = XDocument.Parse(xml, LoadOptions.PreserveWhitespace);
xdoc.DocumentType.InternalSubset = null;
foreach (var formulaNode in xdoc.Descendants("disp-formula"))
{
    var matches = regex.Matches(formulaNode.Value);
    if (matches.Count == 0)
    continue;

    var id = "deqn" + matches[0].Value;
    if (matches.Count &gt; 1)
    id += "-" + matches[matches.Count - 1].Value;

    formulaNode.Attribute("id").Value = id;
}
xdoc.Save(@"C:\Users\Temp\Desktop\test.xml", SaveOptions.DisableFormatting);
File.WriteAllText(@"C:\Users\Temp\Desktop\test.xml", escape_string(xdoc.ToString(), 1));
}

private static string escape_string(string input_string, int option)
{
    switch (option)
    {
        case 0:
        return input_string.Replace("&amp;", "&amp;amp;");
        case 1:
        var x=input_string.Replace(" /&gt;", "/&gt;");
        var y=x.Replace("&amp;amp;", "&amp;");
        var z=y.Replace("\r\n&lt;!DOCTYPE","&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;\r\n&lt;!DOCTYPE");
        return z;

        default:
        return null;

    }
}


The code xdoc.DocumentType.InternalSubset = null; is to stop the Parse() method to create a extra [] in the dtd declaration and also the xml declaration was getting deleted so I added that to a replace in the method escape_string.

Not sure whether it is faster than your posted method though :)

Code for operating on multiple files in a given path (assuming the xml files inside sub-folder 'xml' are only to be processed)

using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;

namespace test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string path = textBox1.Text;
            var files = Directory.GetDirectories(path, "xml", SearchOption.AllDirectories)
                .SelectMany(d =&gt; Directory.GetFiles(d, "*.xml")).ToArray();
            foreach (var file in files)
            {
                try
                {
                    Regex regex = new Regex(@"(?&lt;=\\tag\s?\{)[^\}]+(?=\})");
                    string xml = escape_string(File.ReadAllText(file), 0);
                    var xdoc = XDocument.Parse(xml, LoadOptions.PreserveWhitespace);
                    xdoc.DocumentType.InternalSubset = null;
                    foreach (var formulaNode in xdoc.Descendants("disp-formula"))
                    {
                        var matches = regex.Matches(formulaNode.Value);
                        if (matches.Count == 0)
                            continue;

                        var id = "deqn" + matches[0].Value;
                        if (matches.Count &gt; 1)
                            id += "-" + matches[matches.Count - 1].Value;

                        if (formulaNode.Attribute("id") != null)
                        {
                            formulaNode.Attribute("id").Value = id;
                        }
                        formulaNode.SetAttributeValue("id", id);

                    }
                    xdoc.Save(file, SaveOptions.DisableFormatting);
                    File.WriteAllText(file, escape_string(xdoc.ToString(), 1));
                }
                catch (Exception ex)
                {
                    string filePath = path + @"\Error.log";
                    using (StreamWriter writer = new StreamWriter(filePath, true))
                    {
                        writer.WriteLine(file + ":\r\n---------------------------------------------------\r\n" + ex.Message);
                    }
                }
            }

            MessageBox.Show("Process Complete!");

        }

        private static string escape_string(string input_string, int option)
        {
            switch (option)
            {
                case 0:
                    return input_string.Replace("&amp;", "&amp;amp;");
                case 1:
                    var x = input_string.Replace(" /&gt;", "/&gt;");
                    var y = x.Replace("&amp;amp;", "&amp;");
                    var z = y.Replace("\r\n&lt;!DOCTYPE", "&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;\r\n&lt;!DOCTYPE");
                    return z;

                default:
                    return null;

            }
        }
    }
}