Вы можете создать подкласс XmlReader
, чтобы "отфильтровать" нежелательные элементы, а затем использовать XmlDocument.Load()
со своим считывателем вместо того, чтобы позволять ему создавать свои собственные.
Обратите внимание, что это исключит только значение ошибочных тегов: если вы установите точку останова в цикле Read (), вы обнаружите, что <foo>bar</foo>
состоит из трех частей: <foo>
имеет Элемент NodeType без значения, "bar" имеет Текст NodeType с пустым LocalName, а </foo>
- это EndElement NodeType без значения. Если бы «бар» превышал предельную длину, приведенный ниже «фильтр» превратил бы <foo>bar</foo>
в <foo></foo>
Чтобы исключить все значения <foo>bar</foo>
, основанные на длине «бара», вам придется смотреть в будущее. Выполнимо, но, возможно, не стоит вашего времени. Надеюсь, это не является обязательным требованием.
Альтернативой (или дополнением) этому классу может быть версия этого с Func<string, string>
, через которую проходит каждый Value
: s => (s.Length > MAX_LEN) ? "" : s
.
Кроме того, насколько я знаю, XmlTextReaderImpl
(фактический тип _reader
) может кэшировать весь текст и в любом случае убить вашу производительность. Возможно, вам придется написать свои собственные смелости для этой вещи.
public class FilteredXmlReader : XmlReader
{
public Func<XmlReader, bool> Filter;
private XmlReader _reader;
private FilteredXmlReader(TextReader input, Func<XmlReader, bool> filterProc)
{
Filter = filterProc;
_reader = XmlReader.Create(input);
}
public static new XmlReader Create(TextReader input, Func<XmlReader, bool> filterProc)
{
return new FilteredXmlReader(input, filterProc);
}
public override bool Read()
{
var b = _reader.Read();
while (!(bool)Filter?.Invoke(_reader))
{
b = _reader.Read();
}
return b;
}
#region Wrapper Boilerplate
public override XmlNodeType NodeType => _reader.NodeType;
public override string LocalName => _reader.LocalName;
public override string NamespaceURI => _reader.NamespaceURI;
public override string Prefix => _reader.Prefix;
public override string Value => _reader.Value;
public override int Depth => _reader.Depth;
public override string BaseURI => _reader.BaseURI;
public override bool IsEmptyElement => _reader.IsEmptyElement;
public override int AttributeCount => _reader.AttributeCount;
public override bool EOF => _reader.EOF;
public override ReadState ReadState => _reader.ReadState;
public override XmlNameTable NameTable => _reader.NameTable;
public override string GetAttribute(string name) => _reader.GetAttribute(name);
public override string GetAttribute(string name, string namespaceURI) => _reader.GetAttribute(name, namespaceURI);
public override string GetAttribute(int i) => _reader.GetAttribute(i);
public override string LookupNamespace(string prefix) => _reader.LookupNamespace(prefix);
public override bool MoveToAttribute(string name) => _reader.MoveToAttribute(name);
public override bool MoveToAttribute(string name, string ns) => _reader.MoveToAttribute(name, ns);
public override bool MoveToElement() => _reader.MoveToElement();
public override bool MoveToFirstAttribute() => _reader.MoveToFirstAttribute();
public override bool MoveToNextAttribute() => _reader.MoveToNextAttribute();
public override bool ReadAttributeValue() => _reader.ReadAttributeValue();
public override void ResolveEntity() => _reader.ResolveEntity();
#endregion Wrapper Boilerplate
}
Использование:
var xml = "<test />";
XmlDocument doc = new XmlDocument();
XmlReader rdr = FilteredXmlReader.Create(new System.IO.StringReader(xml),
r => r?.Value.Length < 20);
var filteredXML = doc.OuterXml;