I'm trying to create a program which will search the xml files for nodes in the form <disp-formula id="deqnX-Y">
, create a dictionary where keys are like rid="deqnX" ... rid="deqnY"
, (where X is incremented by +1 till it reaches Y) and their respective value counterparts are like rid="deqnX-Y"
each, Then I can simply do a search and replace using the dictionary to change the link nodes. i.e. if the file has nodes like <disp-formula id="deqn5-7">, <disp-formula id="deqn9-11">, <disp-formula id="deqn3a-3c">, <disp-formula id="deqn4p-5b">
and there are link nodes in the form
<xref ref-type="disp-formula" rid="deqn5"> <xref ref-type="disp-formula" rid="deqn6"> <xref ref-type="disp-formula" rid="deqn10"> <xref ref-type="disp-formula" rid="deqn5c">
which should be changed to
<xref ref-type="disp-formula" rid="deqn5-7"> <xref ref-type="disp-formula" rid="deqn5-7"> <xref ref-type="disp-formula" rid="deqn9-11"> <xref ref-type="disp-formula" rid="deqn4p-5b">
I'm using the below code for now
void Button1Click(object sender, EventArgs e) { string active_filename = ""; string DirectoriesName = textBox1.Text; string[] path = Directory.GetDirectories(DirectoriesName, "xml", SearchOption.AllDirectories) .SelectMany(x => Directory.GetFiles(x, "*.xml", SearchOption.AllDirectories)).ToArray(); Dictionary<string, string> dict = new Dictionary<string, string> (); var re = new Regex(@"deqn(\w+)-(\w+)"); foreach (var file in path) { dict.Clear(); active_filename = file; XDocument doc = XDocument.Load(file, LoadOptions.PreserveWhitespace); IEnumerable<XAttribute> list_of_elements = doc.Descendants("disp-formula").Where(z => (z.Attribute("id") != null) && re.IsMatch(z.Attribute("id").Value)).Attributes("id"); foreach (XAttribute ele in list_of_elements) { int from = 0, to = 0; string strform = re.Match(ele.Value).Groups[1].Value; string strTo = re.Match(ele.Value).Groups[2].Value; Boolean bfrom = int.TryParse(strform,out from); Boolean bto = int.TryParse(strTo,out to); if (bfrom && bto) { for (int i = from; i <= to; i++) dict.Add("rid=\"deqn" + i + "\"", "rid=\"" + ele.Value + "\""); } else { for (int i = base36toInt(strform); i <= base36toInt(strTo); i++) { int temp = 0; if (!int.TryParse(IntTo36Base(i), out temp)) { dict.Add("rid=\"deqn" + IntTo36Base(i) + "\"", "rid=\"" + ele.Value + "\""); } } } foreach (KeyValuePair<string, string> element in dict) { //do a search all replace all (search Key and replace by Value string text = File.ReadAllText(file); text = text.Replace(element.Key, element.Value); File.WriteAllText(file, text); } } } MessageBox.Show("Done"); } public static int base36toInt(string s) { char[] baseChars = "0123456789abcdefghijklmnopqrstuvwxyz".ToCharArray(); char[] target = s.ToCharArray(); double result = 0; for (int i = 0; i < target.Length; i++) { result += Array.IndexOf(baseChars, target[i]) * Math.Pow(baseChars.Length, target.Length - i - 1); } return Convert.ToInt32(result); } public static string IntTo36Base(int value) { char[] baseChars = "0123456789abcdefghijklmnopqrstuvwxyz".ToCharArray(); string result = string.Empty; int targetBase = baseChars.Length; do { result = baseChars[value % targetBase] + result; value = value / targetBase; } while (value > 0); return result; }
But the problem occurs when there are nodes like <disp-formula id="deqn5-7c">
or <disp-formula id="deqn2a-4">
in the file. The error I get is System.IO.IOException: The requested operation cannot be performed on a file with a user-mapped section open. How do I get rid of this error.
Furthermore, I want the program to ignore nodes like <disp-formula id="deqn5-7c">
and/or <disp-formula id="deqn2a-4">
, what is the most efficient way of doing this?
2 Answers
Answers 1
Okay, this might be a stupid answer, but... have you thought about changing your regex? I mean, right now, it's going to match "deqn", followed by any stream of alphanumeric chars, followed by "-", followed by another stream of alphanumerics. So even stuff like "deqnasdf-zxcv" is going to fit.
I'd suggest changing it to: "deqn(\d+)-(\d+)" - aka, change the "any alphanumeric" to "any digit". I mean, if you're wanting to skip the stuff like deqn1-2c anyways, this will prevent them from even showing up in the matches. Plus, the more you narrow down your regex, the more potential bugs you stop in the future for matches you didn't plan for.
Answers 2
I get is System.IO.IOException: The requested operation cannot be performed on a file with a user-mapped section open.
It seems the file that you want change it is using, so you can not change it. Because you say sometimes it happen then I guess your loop is raising the error. It open and close a file fast while you can open the file out of the loop and write to it after the loop. Anyway you can find the app that is using the file when you get the above error by a program such as Process Explorer.
Test it:
Instead of using this code:
foreach (KeyValuePair<string, string> element in dict) { //do a search all replace all (search Key and replace by Value string text = File.ReadAllText(file); text = text.Replace(element.Key, element.Value); File.WriteAllText(file, text); }
Use this one:
string text = File.ReadAllText(file); foreach (KeyValuePair<string, string> element in dict) { //do a search all replace all (search Key and replace by Value text = text.Replace(element.Key, element.Value); } File.WriteAllText(file, text);
0 comments:
Post a Comment