Currently, I'm working on a feature that involves parsing XML that we receive from another product. I decided to run some tests against some actual customer data, and it looks like the other product is allowing input from users that should be considered invalid. Anyways, I still have to try and figure out a way to parse it. We're using javax.xml.parsers.DocumentBuilder and I'm getting an error on input that looks like the following.
<xml>
...
<description>Example:Description:<THIS-IS-PART-OF-DESCRIPTION></description>
...
</xml>
As you can tell, the description has what appears to be an invalid tag inside of it (<THIS-IS-PART-OF-DESCRIPTION>). Now, this description tag is known to be a leaf tag and shouldn't have any nested tags inside of it. Regardless, this is still an issue and yields an exception on DocumentBuilder.parse(...)
I know this is invalid XML, but it's predictably invalid. Any ideas on a way to parse such input?
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's recover=True option.
See also this answer for how to use codecs.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 that XmlReader 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”.
Go: Set Decoder.Strict to false as shown in this example by #chuckx.
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, '')
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.
A standard XML parser will NEVER accept invalid XML, by design.
Your only option is to pre-process the input to remove the "predictably invalid" content, or wrap it in CDATA, prior to parsing it.
The accepted answer is good advice, and contains very useful links.
I'd like to add that this, and many other cases of not-wellformed and/or DTD-invalid XML can be repaired using SGML, the ISO-standardized superset of HTML and XML. In your case, what works is to declare the bogus THIS-IS-PART-OF-DESCRIPTION element as SGML empty element and then use eg. the osx program (part of the OpenSP/OpenJade SGML package) to convert it to XML. For example, if you supply the following to osx
<!DOCTYPE xml [
<!ELEMENT xml - - ANY>
<!ELEMENT description - - ANY>
<!ELEMENT THIS-IS-PART-OF-DESCRIPTION - - EMPTY>
]>
<xml>
<description>blah blah
<THIS-IS-PART-OF-DESCRIPTION>
</description>
</xml>
it will output well-formed XML for further processing with the XML tools of your choice.
Note, however, that your example snippet has another problem in that element names starting with the letters xml or XML or Xml etc. are reserved in XML, and won't be accepted by conforming XML parsers.
IMO these cases should be solved by using JSoup.
Below is a not-really answer for this specific case, but found this on the web (thanks to inuyasha82 on Coderwall). This code bit did inspire me for another similar problem while dealing with malformed XMLs, so I share it here.
Please do not edit what is below, as it is as it on the original website.
The XML format, requires to be valid a unique root element declared in the document.
So for example a valid xml is:
<root>
<element>...</element>
<element>...</element>
</root>
But if you have a document like:
<element>...</element>
<element>...</element>
<element>...</element>
<element>...</element>
This will be considered a malformed XML, so many xml parsers just throw an Exception complaining about no root element. Etc.
In this example there is a solution on how to solve that problem and succesfully parse the malformed xml above.
Basically what we will do is to add programmatically a root element.
So first of all you have to open the resource that contains your "malformed" xml (i. e. a file):
File file = new File(pathtofile);
Then open a FileInputStream:
FileInputStream fis = new FileInputStream(file);
If we try to parse this stream with any XML library at that point we will raise the malformed document Exception.
Now we create a list of InputStream objects with three lements:
A ByteIputStream element that contains the string: <root>
Our FileInputStream
A ByteInputStream with the string: </root>
So the code is:
List<InputStream> streams =
Arrays.asList(
new ByteArrayInputStream("<root>".getBytes()),
fis,
new ByteArrayInputStream("</root>".getBytes()));
Now using a SequenceInputStream, we create a container for the List created above:
InputStream cntr =
new SequenceInputStream(Collections.enumeration(str));
Now we can use any XML Parser library, on the cntr, and it will be parsed without any problem. (Checked with Stax library);
Could anyone please help in getting the ampersand "&" output of Transform xml activity of TIBCO .
My requirement is the xmlstring from Transform xml activity is mapped to Parse xml (which will give the final output ) .Ex; Maitree&Sons. What should be passed in xslt so that when the output from Transform xml goes to Parse xml it will give the final result as "&".
I tried using CDATA and disable-escaping-output also in xslt but in parse xml it fails.
Please help.
Generally XSLT won't allow you to produce invalid output. The correct representation in XML is Maitree&Sons and this is what it produces. If it produced Maitree&Sons, this would be invalid XML and would be thrown out by an XML parser trying to read the document.
Having said that, it's possible using disable-output-escaping to produce an unescaped ampersand if your XSLT processor supports this option. If it's not working for you we need to know exactly what you did and how it failed.
(General rule: on SO, always tell us exactly what you did and exactly how it failed. Saying in general terms that you tried lots of things and none of them worked doesn't get us any nearer to a solution.)
LATER
I'm reading the question again. You want to produce output from the transformer that will go into an XML parser, such that the output of the parser is Maitree&Sons. Well, in that case the lexical XML must be Maitree&Sons, which it will be if you generate the string Maitree&Sons in XSLT. But XSLT is XML, so if you want to write this as a literal string in your stylesheet, it will be written Maitree&Sons.
I guess we need a much clearer picture of what you are doing and where it is going wrong.
I have a file with a lot of xml nodes and they are linked together with an id. I need to change the id of a node as well as the link.
<event id="12345">
<action>6789</action>
</event>
<action id="6789">
<name>pre-filter1</name>
<someotherlink>45678</someotherlink>
</action>
I need to change the id of action nodes and the reference wherever it is being linked from. I was looking into regex because I have to do it for some action nodes only with some specific name like pre-filter here. the id needs to be processed by some logic before replacing with the new value. the order of nodes is random.
I only need to do it once for the whole file and any way is fine. also time complexity is not a constraint.
Any help is appreciated.
Perl supports using functions on the replacement of a regular expression. Not sure about other languages.
If you are not using perl, you may do the following:
1) Get all action ids for a given name with this regexp:
<action\s*id="(\d+)">(?=[^=]*<name>pre-filter\d<\/name>).*?<\/action>
https://regex101.com/r/Q7lKgx/1
2) Convert values and store both original id and converted value in a hash.
3) Loop the hash and use a regexp to replace the id with the new value
This matches both action and action id:
(<action(?:\s*id="|>))(THE_ID)("|<\/action)> ==> replace with \1NEW_ID\3
Anyways, parsing XML with regexes is usually not a good idea, so It would be even better to use some library to parse xmls.
I have multiple XML files that contain various strings. I also have a text file of strings, some of which are contained within the XML files.
XML:
text="$$sRegister $$s is stuck at One. (VDB-5014)" uid="5014"/>
String File:
is stuck at one
I would like to print the strings that are both in my string file and my XML file. This way I can set the correct message type in the XML file. Given the high volume of messages I've been attempting to automate this process. Thoughts?
You can use grep -f:
grep -f stringFile xmlFile
I am using XSLT to generate an .sql file from an .xml input file.
I have some problems with the indentation.
The way the stylesheet is formatted (how many line feeds and carriage returns and tabs) directly effects the output file i.e. if I include a few line feeds and CRs in my stylesheet to make it more readable, they are displayed in the output file as well (this would not be that bad if the tabs didn't affect the formatting of the output file as well):
It looks like this:
SQLStatement1<CR><LF>
<CR><LF>
<CR><LF>
SQLStatement2<CR><LF>
.... (tabs are also outputted)
I use an ant task to create the .sql file. The target looks like this:
<xslt in="input.xml"
out="queries.sql"
style="createQueries.xls">
</xslt>
I am using XSLT 1.0 and cannot use XSLT 2.0.
I thought about modifying some output parameters. However it does not have any effect if I change the method attribute to e.g. 'html' (I guess that the method is set to 'text' since the type of the output file(sql) is not known)
Any ideas on how to fix this issue?
Cheers
You would make it much easier on us if you showed a small but complete XML input sample, an XSLT sample, the output you get and the output you want.
If you use xsl:output method="text" and want to control the white space then make sure you use xsl:text to output literal text and xsl:value-of to output computed text. That way you should be able to control the white space exactly.