3
votes

I want to generate a nested entity DTD declaration on top of an XML document with XMLWriter. I started with just string-building code w/o XMLWriter which illustrates the desired output as well:

<?php
$sXML = "<!DOCTYPE Example PUBLIC \"urn:example:example.org:20110823:Example\"\n";
$sXML .= "\"http://www.example.org/example.dtd\" [\n";
$sXML .= "<!ENTITY % nestedentity SYSTEM ";
$sXML .= "\"http://www.example.org/nestedentity.dtd\">\n";
$sXML .= "%nestedentity;\n";
$sXML .= "]>\n";

Current (Desired) $sXML Output:

<!DOCTYPE Example PUBLIC "urn:example:example.org:20110823:Example"
"http://www.example.org/example.dtd" [
<!ENTITY % anentity SYSTEM "http://www.example.org/nestedentity.dtd">
%anentity;
]>

Current XMLWriter $sXML Output (code below):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Example
PUBLIC "urn:example:example.org:20110823:Example"
       "http://www.example.org/example.dtd" [
        <!ENTITY % anentity PUBLIC "" "http://www.example.org/nestedentity.dtd">
]>

As you can see, the current XMLWriter code XML output has the following issues:

  1. the nested entity reference as PUBLIC, not SYSTEM
  2. has an empty string before the desired SYSTEM identifier
  3. does not inline the entity expansion string, '%anentity;', prior to closing the DOCTYPE declaration.

So, the question is, how do I call $oXMLWriter->writeDtdEntity such that the XML string displayed in the "Current (Desired) $sXML Output" section is displayed (ignoring differences purely in whitespace)?

Current XMLWriter Code:

<?php
$oWriter = new XMLWriter();
$oWriter->openMemory();
$oWriter->setIndent(true);
$oWriter->setIndentString("\t");
$oWriter->startDocument("1.0", "UTF-8");
$oWriter->startDtd('Example','urn:example:example.org:20110823:Example', 'http://www.example.org/example.dtd');
$oWriter->writeDtdEntity(
    'nestedentity',
    '%nestedentity;\n',
    true,
    null,
    'http://www.example.org/nestedentity.dtd'
);
$oWriter->endDtd();
$oWriter->endDocument();
$sXML = $oWriter->outputMemory();
1

1 Answers

2
votes

Well I'm not an expert in DTDs but I notice a couple of mistakes:

Just a short example with:

$oWriter = new XMLWriter();
$oWriter->openMemory();
$oWriter->setIndent(true);
$oWriter->setIndentString("\t");
$oWriter->startDocument("1.0", "UTF-8");
    // use null for $publicID to force SYSTEM
    $oWriter->startDtd('Example', null, 'http://www.example.org/example.dtd');
    $oWriter->writeDTDEntity('foo', 'bar');
    $oWriter->endDtd();
$oWriter->endDocument();
$sXML = $oWriter->outputMemory();

And the result is as expected (notice the SYSTEM instead of PUBLIC):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Example
SYSTEM "http://www.example.org/example.dtd" [
    <!ENTITY foo "bar">
]>