That is very unfortunate. Until a better solution appears I've crafted a CleaningStreamReader (C#) that replaces any illegal character sequence with the space sequence so that at least the XmlReader can process the whole file.
The implementation really needs some StateMachine for cases where the characters are split across two reads. But that is for vNext and when we agree this is something that can work. Alternatively the FileStream itself can be cleaned but then you have similar problems but at the UTF8 Encoding for up to 4 bytes.
public class CleaningStreamReader:StreamReader
{
public CleaningStreamReader(Stream fs, Encoding enc):base(fs,enc) {
}
public override int Read (char[] buffer, int index, int count)
{
var charcount = base.Read(buffer, index,count);
for( var i = index; i < index+charcount; i++) {
// this really needs a state machine because we might not have all chars we need in this current buffer
// check if  till  exists, replace 1F with 20
if ((i + 5 < index + charcount) && buffer[i] == '&' && buffer[i+1] == '#' && buffer[i+2] == 'x' && buffer[i+5] == ';')
{
if ((buffer[i+3] == '0' || buffer[i+3] == '1' ) && (buffer[i+4] >= '0' && buffer[i+4] <= 'F')) {
buffer[i+3] = '2'; buffer[i+4] = '0';
}
}
}
return charcount;
}
}
And here is how you use that class:
var filename = @"\some\path\3dprinting.stackexchange.com\posthistory.xml";
var nodes = new Dictionary<XmlNodeType, int>();
using(var fs = File.OpenRead(filename))
using(var sr = new CleaningStreamReader(fs, Encoding.UTF8))
using(var xr = XmlReader.Create(sr)) {
while(xr.Read()) {
if (nodes.Keys.Contains(xr.NodeType)) {
nodes[xr.NodeType] = nodes[xr.NodeType] +1 ;
} else {
nodes.Add(xr.NodeType, 1);
}
if (xr.NodeType == XmlNodeType.Element) {
bool ha = xr.MoveToFirstAttribute();
while(ha) {
if (nodes.Keys.Contains(xr.NodeType)) {
nodes[xr.NodeType] = nodes[xr.NodeType] +1 ;
} else {
nodes.Add(xr.NodeType, 1);
}
ha = xr.MoveToNextAttribute();
}
}
}
}
nodes.Dump();
This is what statistics of NodeTypes will look like when you processed the 3d printing PostHistory.xml successfully:
#x1E;
being invalid. I recognize it's a non-printing character, and when I try to use it it in a browser's XML parser, I do indeed get an error "xmlParseCharRef: invalid xmlChar value 30". But the XML specification for Character References only says it has to refer to a valid Char, where Char is defined as "any Unicode character, excluding the surrogate blocks", and although document authors are "encouraged to avoid" characters such as#x1E;
, it's not clear to me where it's defined as an error.<?xml version="1.0" encoding="utf-8"?>