PE Reference splitting in INCLUDE-section
"Dr. Stefan Bettner" <[email protected]> Tue, 21 Sep 2021 19:48:58 +0200
| Newsgroups | gmane.text.xml.xerces-j.user |
|---|---|
| Message-ID | <[email protected]> |
Hi everybody,
I have a question regarding the Java xml parser. I have some behavior
that baffles me, regarding the replacement text of parameter entity
references within a conditional INCLUDE-section. And I would really be
grateful if someone could explain it to me.
When I look into the xml specification (fifth edition), they state:
"Well-formedness constraint: PE Between Declarations
The replacement text of a parameter entity reference in a DeclSep MUST
match the production extSubsetDecl."
That prevents for example to split a markup declaration into the
replacement text of two separate parameter entities. Like for example
the entity-declaration
<!ENTITY copyright '(C)'>
cannot be split into two parameter entity references like that:
<!ENTITY % A "<!ENTITY ">
<!ENTITY % B "copyright '(C)'>">
%A;%B;
because in that case the replacement text for %A; would not match the
production extSubsetDecl (as required), because it is incomplete.
And the Java xml-parser reports the above as a fatal error, in
validation and non-validation-mode alike. So far so good.
But strangely the situation changes when the expression %A;%B; is put
into a conditional INCLUDE-section, like that:
<!ENTITY % A "<!ENTITY ">
<!ENTITY % B "copyright '(C)'>">
<![INCLUDE[%A;%B;]]>
In that case the Java xml-parser has no problem at all with the above in
non-validation-mode, and in validation-mode only two validation errors
are given, but no fatal error. In both cases the entity "copyright" is
declared and can be used within the document.
How can that be? I would really be grateful if someone could explain
that to me.
When I look at the grammatical definition of a conditional include-section
[62]=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 includeSect=C2=A0=C2=A0=C2=A0 =C2=A0=
=C2=A0 ::=3D=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 '<![' S? 'INCLUDE' S? '['
extSubsetDecl ']]>'
the inner part should be an extSubsetDecl. So with looking at
[31]=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 extSubsetDecl=C2=A0=C2=A0=C2=A0 =C2=A0=
=C2=A0 ::=3D=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 ( markupdecl | conditionalSect
| DeclSep)*
in our case, when processing the INCLUDE-section, %A; can only match a
DeclSep, and with the well-formedness constraint meantioned above, I
would have assumed that the replacement text of %A; "MUST match the
production extSubsetDecl". But it does not, since the replacement text
of %A; is incomplete.
I would be grateful for any hint.
Thank you so much for your work.
Apache is such a great project.
Bye everybody.
Stay healthy you all.
Stefan Bettner.
PS: I appended my xml files and Java file, for comparison. I was using
the following Java-version on Windows 10:
java version "12.0.2" 2019-07-16
Java(TM) SE Runtime Environment (build 12.0.2+10)
splitEntity.xml
<?xml version=3D"1.0" encoding=3D"UTF-8"?>
<!DOCTYPE Root SYSTEM "splitEntity.dtd" [
<!ELEMENT Root ANY>
] >
<Root>©right;</Root>
splitEntity.dtd
<!ENTITY % A "<!ENTITY ">
<!ENTITY % B "copyright '(C)'>">
<![INCLUDE[%A;%B;]]>
XMLSplitEntity.java
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
public class XMLSplitEntity
=C2=A0 {
=C2=A0 /*
=C2=A0=C2=A0 * custom DocumentHandler
=C2=A0=C2=A0 */
=C2=A0 public static class MyDocumentHandler extends DefaultHandler
=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0 @Override
=C2=A0=C2=A0=C2=A0 public void characters (char[] ch, int start, int leng=
th) throws
SAXException
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 System.out.println ("characters: " + new S=
tring (ch, start, length));
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 @Override
=C2=A0=C2=A0=C2=A0 public void warning (SAXParseException e) throws SAXEx=
ception
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 System.out.println ("warning: " + e.getMes=
sage ());
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 @Override
=C2=A0=C2=A0=C2=A0 public void error (SAXParseException e) throws SAXExce=
ption
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 System.out.println ("error: " + e.getMessa=
ge ());
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 @Override
=C2=A0=C2=A0=C2=A0 public void fatalError (SAXParseException e) throws SA=
XException
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 System.out.println ("fatalError: " + e.get=
Message ());
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 }
=C2=A0 /*
=C2=A0=C2=A0 * parse splitEntity.xml
=C2=A0=C2=A0 * (with external splitEntity.dtd)
=C2=A0=C2=A0 */
=C2=A0 public static void main (String[] args)
=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0 // create parser
=C2=A0=C2=A0=C2=A0 SAXParserFactory factory =3D SAXParserFactory.newInsta=
nce ();
=C2=A0=C2=A0=C2=A0 // factory.setValidating (true);
=C2=A0=C2=A0=C2=A0 SAXParser saxParser;
=C2=A0=C2=A0=C2=A0 try
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 saxParser =3D factory.newSAXParser ();
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 catch (ParserConfigurationException | SAXException e)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 e.printStackTrace ();
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 // parse
=C2=A0=C2=A0=C2=A0 File file =3D new File ("C:\\splitEntity.xml");
=C2=A0=C2=A0=C2=A0 try
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 saxParser.parse (file, new MyDocumentHandl=
er ());
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 catch (SAXException | IOException e)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 e.printStackTrace ();
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 }
=C2=A0 }