That “XML” is worse than invalid – it’s not well-formed; see Well Formed vs Valid XML.
An informal assessment of the predictability of the transgressions does not help. That textual data is not XML. No conformant XML tools or libraries can help you process it.
Options, most desirable first:
-
Have the provider fix the problem on their end. Demand well-formed XML. (Technically the phrase well-formed XML is redundant but may be useful for emphasis.)
-
Use a tolerant markup parser to cleanup the problem ahead of parsing as XML:
-
Standalone: xmlstarlet has robust recovering and repair capabilities credit: RomanPerekhrest
xmlstarlet fo -o -R -H -D bad.xml 2>/dev/null
-
Standalone and C/C++: HTML Tidy works with XML too. Taggle is a port of TagSoup to C++.
-
Python: Beautiful Soup is Python-based. See notes in the Differences between parsers section. See also answers to this question for more
suggestions for dealing with not-well-formed markup in Python,
including especially lxml’srecover=True
option.
See also this answer for how to usecodecs.EncodedFile()
to cleanup illegal characters. -
Java: TagSoup and JSoup focus on HTML.
FilterInputStream
can be used for preprocessing cleanup. -
.NET:
- XmlReaderSettings.CheckCharacters can
be disabled to get past illegal XML character problems. - @jdweng notes that
XmlReaderSettings.ConformanceLevel
can be set to
ConformanceLevel.Fragment
so thatXmlReader
can read XML Well-Formed Parsed Entities lacking a root element. - @jdweng also reports that
XmlReader.ReadToFollowing()
can sometimes
be used to work-around XML syntactical issues, but note
rule-breaking warning in #3 below. Microsoft.Language.Xml.XMLParser
is said to be “error-tolerant”.
- XmlReaderSettings.CheckCharacters can
-
PHP: See DOMDocument::$recover and libxml_use_internal_errors(true). See nice example here.
-
Ruby: Nokogiri supports “Gentle Well-Formedness”.
-
R: See htmlTreeParse() for fault-tolerant markup parsing in R.
-
Perl: See XML::Liberal, a “super liberal XML parser that parses broken XML.”
-
-
Process the data as text manually using a text editor or
programmatically using character/string functions. Doing this
programmatically can range from tricky to impossible as
what appears to be
predictable often is not — rule breaking is rarely bound by rules.-
For invalid character errors, use regex to remove/replace invalid characters:
- PHP:
preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $s);
- Ruby:
string.tr("^\u{0009}\u{000a}\u{000d}\u{0020}-\u{D7FF}\u{E000}-\u{FFFD}", ' ')
- JavaScript:
inputStr.replace(/[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm, '')
- PHP:
-
For ampersands, use regex to replace matches with
&
: credit: blhsin, demo&(?!(?:#\d+|#x[0-9a-f]+|\w+);)
-
Note that the above regular expressions won’t take comments or CDATA
sections into account.