[DOC-CVS] [phd] translatable-acronyms: simplify acronym parsing with SimpleXML

[email protected] (Jordi Kroon) Wed, 22 Jul 2026 19:33:24 +0000
Newsgroups php.doc.cvs
Message-ID <[email protected]>
Author: Jordi Kroon (jordikroon)
Date: 2026-07-22T21:32:57+02:00

Commit: https://github.com/php/phd/commit/e059fdc822832dafadd4acc2839af38265daabc6
Raw diff: https://github.com/php/phd/commit/e059fdc822832dafadd4acc2839af38265daabc6.diff

simplify acronym parsing with SimpleXML

Changed paths:
  A  tests/package/php/data/entities.acronyms.ent
  D  tests/package/php/data/acronyms.ent
  M  phpdotnet/phd/Package/PHP/XHTML.php
  M  render.php
  M  tests/package/php/acronym_info_001.phpt


Diff:

diff --git a/phpdotnet/phd/Package/PHP/XHTML.php b/phpdotnet/phd/Package/PHP/XHTML.php
index 1608bfd5..53a78c9c 100644
--- a/phpdotnet/phd/Package/PHP/XHTML.php
+++ b/phpdotnet/phd/Package/PHP/XHTML.php
@@ -336,53 +336,29 @@ public static function generateAcronymInfo($filename) {
         if ($info) {
             return $info;
         }
+
         if (!is_file($filename)) {
             trigger_error(vsprintf("Can't find acronym file (%s), skipping", [$filename]), E_USER_WARNING);
             return array();
         }
 
-        $subset = file_get_contents($filename);
-        if ($subset === false) {
-            throw new \Error(vsprintf('Could not open file for accessing acronym information (%s)', [$filename]));
-        }
-
-        // libxml only exposes entity content once referenced, so collect
-        // the acronym.* entity names first, then reference each of them.
         $useInternalErrors = libxml_use_internal_errors(true);
-        $dom = new \DOMDocument;
-        $loaded = $dom->loadXML("<!DOCTYPE acronyms [" . $subset . "]><acronyms/>");
-        if (!$loaded) {
-            libxml_clear_errors();
-            libxml_use_internal_errors($useInternalErrors);
-            trigger_error(vsprintf("Can't parse acronym file (%s), skipping", [$filename]), E_USER_WARNING);
-            return [];
-        }
-
-        $names = [];
-        foreach ($dom->doctype->entities as $entity) {
-            if (str_starts_with($entity->nodeName, "acronym.")) {
-                $names[] = $entity->nodeName;
-            }
-        }
-
-        $body = "";
-        foreach ($names as $name) {
-            $body .= '<acronym name="' . $name . '">&' . $name . ';</acronym>';
-        }
-        $dom = new \DOMDocument;
-        $loaded = $dom->loadXML("<!DOCTYPE acronyms [" . $subset . "]><acronyms>" . $body . "</acronyms>", LIBXML_NOENT);
+        $entities = simplexml_load_file($filename);
         libxml_clear_errors();
         libxml_use_internal_errors($useInternalErrors);
-        if (!$loaded) {
-            trigger_error(vsprintf("Can't expand acronym entities (%s), skipping", [$filename]), E_USER_WARNING);
+        if ($entities === false) {
+            trigger_error(vsprintf("Can't parse acronym file (%s), skipping", [$filename]), E_USER_WARNING);
             return [];
         }
 
         $acronyms = [];
-        foreach ($dom->documentElement->childNodes as $node) {
-            $acronym = substr($node->getAttribute("name"), strlen("acronym."));
-            $acronyms[$acronym] = trim(preg_replace('/\s+/', ' ', $node->textContent));
+        foreach ($entities as $entity) {
+            $name = (string) $entity["name"];
+            if (str_starts_with($name, "acronym.expansion.")) {
+                $acronyms[substr($name, strlen("acronym.expansion."))] = trim(preg_replace('/\s+/', ' ', (string) $entity));
+            }
         }
+
         ksort($acronyms);
         $info = $acronyms;
         return $acronyms;
diff --git a/render.php b/render.php
index 7ef4ae02..15f8c7b8 100644
--- a/render.php
+++ b/render.php
@@ -61,12 +61,21 @@
 
 // This needs to be moved. Preferably into the PHP package.
 if (!$conf) {
+    // Acronym expansions come from the translatable entity file in the
+    // language checkout (e.g. en/, it/), languages without a
+    // translated copy fall back to the English one.
+    $acronymFilename = dirname($config->xmlRoot) . DIRECTORY_SEPARATOR . $config->language
+                        . DIRECTORY_SEPARATOR . 'entities' . DIRECTORY_SEPARATOR . 'entities.acronyms.ent';
+    if (!is_file($acronymFilename)) {
+        $acronymFilename = dirname($config->xmlRoot) . DIRECTORY_SEPARATOR . 'en'
+                            . DIRECTORY_SEPARATOR . 'entities' . DIRECTORY_SEPARATOR . 'entities.acronyms.ent';
+    }
     $config->init(array(
         "langDir"  => __INSTALLDIR__ . DIRECTORY_SEPARATOR . "phpdotnet" . DIRECTORY_SEPARATOR
                         . "phd" . DIRECTORY_SEPARATOR . "data" . DIRECTORY_SEPARATOR
                         . "langs" . DIRECTORY_SEPARATOR,
         "phpwebVersionFilename" => $config->xmlRoot . DIRECTORY_SEPARATOR . 'version.xml',
-        "phpwebAcronymFilename" => $config->xmlRoot . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . 'entities.ent',
+        "phpwebAcronymFilename" => $acronymFilename,
         "phpwebSourcesFilename" => $config->xmlRoot . DIRECTORY_SEPARATOR . 'sources.xml',
         "phpwebHistoryFilename" => $config->xmlRoot . DIRECTORY_SEPARATOR . 'fileModHistory.php',
     ));
@@ -108,7 +117,7 @@
     $outputHandler->v("Indexing...", VERBOSE_INDEXING);
     // Create indexer
     $format = new Index($config->indexCache, $config, $outputHandler);
-    
+
     $render->attach($format);
 
     $outputHandler->v("Running full build", VERBOSE_RENDER_STYLE);
diff --git a/tests/package/php/acronym_info_001.phpt b/tests/package/php/acronym_info_001.phpt
index a889d33f..b015243d 100644
--- a/tests/package/php/acronym_info_001.phpt
+++ b/tests/package/php/acronym_info_001.phpt
@@ -1,12 +1,12 @@
 --TEST--
-Acronym info 001 - Acronyms are read from acronym.* XML entities
+Acronym info 001 - Acronyms are read from acronym.expansion.* entity elements
 --FILE--
 <?php
 namespace phpdotnet\phd;
 
 require_once __DIR__ . "/../../setup.php";
 
-$acronyms = Package_PHP_XHTML::generateAcronymInfo(__DIR__ . "/data/acronyms.ent");
+$acronyms = Package_PHP_XHTML::generateAcronymInfo(__DIR__ . "/data/entities.acronyms.ent");
 
 var_dump($acronyms);
 ?>
diff --git a/tests/package/php/data/acronyms.ent b/tests/package/php/data/acronyms.ent
deleted file mode 100644
index 53eda86b..00000000
--- a/tests/package/php/data/acronyms.ent
+++ /dev/null
@@ -1,16 +0,0 @@
-
-<!-- DO NOT COPY / DO NOT TRANSLATE -->
-<!-- Autogenerated by text-entities.php -->
-
-<!ENTITY sample.other 'Some other, non acronym, entity'>
-
-<!ENTITY acronym.API 'Application Programming Interface'>
-
-<!ENTITY acronym.CSPRNG '
- Cryptographically Secure
- PseudoRandom Number Generator
-'>
-
-<!ENTITY acronym.PHP 'PHP: Hypertext Preprocessor'>
-
-<!ENTITY acronym.cURL 'Client URL Library'>
diff --git a/tests/package/php/data/entities.acronyms.ent b/tests/package/php/data/entities.acronyms.ent
new file mode 100644
index 00000000..a657a3cf
--- /dev/null
+++ b/tests/package/php/data/entities.acronyms.ent
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- $Revision$ -->
+
+<entities xmlns       = "http://docbook.org/ns/docbook"
+          xmlns:xlink = "http://www.w3.org/1999/xlink"
+          translate   = "yes">
+
+<entity name="sample.other">Some other, non acronym, entity</entity>
+
+<entity name="php"><acronym>PHP</acronym></entity>
+
+<entity name="acronym.expansion.API">Application Programming Interface</entity>
+
+<entity name="acronym.expansion.CSPRNG">
+ Cryptographically Secure
+ PseudoRandom Number Generator
+</entity>
+
+<entity name="acronym.expansion.PHP">PHP: Hypertext Preprocessor</entity>
+
+<entity name="acronym.expansion.cURL">Client URL Library</entity>
+
+</entities>