Using the .Net framework, I need to read XML entity text as raw string values (character entities not expanded) for use in a comparison / merge function. As far as I can tell, there's no way of directly turning off character entity expansion.
I've tried deriving from XmlTextReader and hooking the Read() method, which does intercept reads, but the Value property is read-only and I can't see any way of modifying the incoming text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace blah {
class XmlRawTextReader : XmlTextReader {
public XmlRawTextReader(string fileName) : base(fileName) { }
public override bool Read() {
bool result = base.Read();
if (result == true && base.HasValue && base.NodeType == XmlNodeType.Text) {
string s = this.Value;
//this.Value = @"new value"; // does not work - read-only
}
return result;
}
}
}
Does anyone know how to either disable character entity expansion or updating strings at the point they're read?
Kinda stuck here so thanks in advance for ideas...
After putting this on the back-burner for a while, the answer became apparent:
Although you can't easily override the Read() method to change the read value, you can hook the property accessor to do the same thing:
using System;
using System.Collections.Generic;
using System.Xml;
namespace blah {
class XmlCustomTextReader : XmlTextReader {
private Func<string, List<KeyValuePair<string, string>>, string> _updateFunc;
public XmlCustomTextReader(string fileName, Func<string, List<KeyValuePair<string, string>>, string> updateFunc = null) : base(fileName) {
_updateFunc = updateFunc;
}
//
// intercept and override value access - 'un-mangle' strings that were rewritten by XMLTextReader
public override string Value {
get {
string currentvalue = base.Value;
// only text nodes
if (NodeType != XmlNodeType.Text)
return currentvalue;
string newValue = currentvalue;
// if a conversion function was provided, use it to update the string
if (_updateFunc != null)
newValue = _updateFunc(currentvalue, null);
return newValue;
}
}
}
}
Use this by:
Func<string, List<KeyValuePair<string, string>>, string> updateFunc = UpdateString;
XmlCustomTextReader reader = new XmlCustomTextReader(fileName, updateFunc);
reader.XmlResolver = new XmlCustomResolver(XmlCustomResolver.ResolverType.useResource);
XDocument targetDoc = XDocument.Load(reader);
I hope this helps someone in the future...