Skip to content
Advertisement

How can I show XML external entities in a php page?

I am currently working on a little library project using XML to define books, and php to do a search using title/author then showing that specific book in the browser. So I made a bunch of books in XML files, then linked those files as external entities in my main XML file. I used a DTD to define the entities, and a XSD file to define the scheme for my xml file (I am required to use the XSD, but it doesn’t let me define entities so I made a DTD too). All the files were validated, and when showing a single book, or if I put all the books in the same xml file without using entities, it works just fine. But when I try using the main xml file that contain just entities, It doesn’t recognize them, and gives me the following warnings without showing anything:

Warning: simplexml_load_file(): test.xml:6: parser error : Entity ‘book1’ not defined in C:xampphtdocsxmltest.php on line 14

Warning: simplexml_load_file(): &book1; in C:xampphtdocsxmltest.php on line 14

My php script is the following :

<?  $xml=simplexml_load_file("test.xml") or die("Error: Cannot create object");
     foreach($xml->children() as $books) {?>
     <b>Title:</b> <span id = "title"><? echo $books->title?></span><br>
     <b>Authors:</b> <span id = "authors"><? echo $books->authors?></span><br>
     <b>Publication date:</b> <span id = "pdate"><? echo $books->publication_date?></span><br>
     <b>Publisher:</b> <span id = "publisher"><? echo $books->publisher?></span>
     <?}?>

And my main XML is like this (with that &book repeating for each of my books):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="test.xsl "?>
<!DOCTYPE biblio SYSTEM "test.dtd">
<biblio xsi:noNamespaceSchemaLocation="test.xsd"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
&book1;
&book2;
&book3;
</biblio>

Following are the DTD:

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT biblio (livre+)> 
<!ATTLIST biblio
      xsi:noNamespaceSchemaLocation CDATA #IMPLIED
      xmlns:xsi CDATA #IMPLIED>
<!ELEMENT livre (bookID,title,authors,publication_date?,publisher*)>
<!ELEMENT bookID (#PCDATA)>
<!ELEMENT title (#PCDATA)> 
<!ELEMENT authors (#PCDATA)>
<!ELEMENT publication_date (#PCDATA)> 
<!ELEMENT publisher (#PCDATA)> 
<!ENTITY book1 SYSTEM "book1.xml">
<!ENTITY book2 SYSTEM "book2.xml">
<!ENTITY book3 SYSTEM "book3.xml">

And XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:element name="biblio">
    <xsd:complexType>
        <xsd:sequence> 
            <xsd:element name= "livre" maxOccurs="unbounded">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="bookID" type="xsd:integer"/>
                        <xsd:element name="title" type="xsd:string"/>
                        <xsd:element name="authors" type="xsd:string"/>
                        <xsd:element name="publication_date" type="xsd:date"/>
                        <xsd:element name="publisher" type="xsd:string"/>
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element> 
        </xsd:sequence> 
    </xsd:complexType>
</xsd:element>
</xsd:schema>

And finally, here is a sample of my book.xml:

<?xml version="1.0" encoding="UTF-8"?>
<livre>
<bookID>1</bookID>
<title>Harry Potter and the Half-Blood Prince (Harry Potter  #6)</title>
<authors>J.K. Rowling/Mary GrandPré</authors>
<publication_date>2006-09-16</publication_date>
<publisher>Scholastic Inc.</publisher>
</livre>

PS: I am using xampp to run php on browser.

EDIT : after some tests, I came to understand that the way I store the file, it just shows everything it contains and doesn’t read it like I do, I tried running the php in a cmd prompt and I could see that it prints the xml file as it is, so I guess I should find a way to specify how it should interpret the xml file content.

EDIT 2: I changed to simpleXML , now I can show the books infos as I want , but I can’t figure out how to show the entities content.

Advertisement

Answer

Well I found a solution to my problem , I had to use the SimpleXMLElement attribute and some libxml options in the simplexml_load_file function , like this:

      $xml=simplexml_load_file("test.xml",'SimpleXMLElement', LIBXML_DTDLOAD | LIBXML_NOENT) or die("Error: Cannot create object");
      foreach($xml->children() as $books) {?>
      <b>Title:</b> <span id = "title"><? echo $books->title?></span><br>
      <b>Authors:</b> <span id = "authors"><? echo $books->authors?></span><br>
      <b>Publication date:</b> <span id = "pdate"><? echo $books->publication_date?></span><br>
      <b>Publisher:</b> <span id = "publisher"><? echo $books->publisher?></span>
      <?}?> 

The first one LIBXML_DTDLOAD Load the external subset and the second LIBXML_NOENT Substitute entities as stated in the official documentation : https://www.php.net/manual/en/libxml.constants.php .

NB: to use multiple LIBXML constants you should separate them by a pipe. (Thanks to the first note in this documentation : https://www.php.net/manual/en/function.simplexml-load-string.php#101594 )

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement