0

When I apply an XSLT template to a TEI XML file using PHP it seems that PHP can't navigate the XML tree using X-Path, because it seems to ignore (all) elements inside the XML file.

In PHP, I am trying to use an XSLT file to transform a TEI XML file that contains different apparat entries like this:

<app>
    <rdg wit="#P1 #P2 #P3"/>
    <rdg wit="#A #B #G #M #V">
        <app>
            <rdg wit="#B #G #M #V" type="order">Sermo septimus
                <app>
                    <rdg wit="#B #M #V">adhuc</rdg>
                    <rdg wit="#G"/>
                </app>
            </rdg>
            <rdg wit="#A" type="order">Septimus adhuc sermo</rdg>
        </app>
        de nomine
        <app>
            <rdg wit="#B #G #M #V"/>
            <rdg wit="#A">Jesu</rdg>
        </app>
        gratioso
        <app>
            <rdg wit="#B #M #V">propter
                <app>
                    <rdg wit="#M #V">tres</rdg>
                    <rdg wit="#B"/>
                </app>
                virtutes theologicas</rdg>
            <rdg wit="#A #G"/>
        </app>
    </rdg>
</app>

To illustrate the problem I created a simplified XSLT like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/1999/xhtml"
  xpath-default-namespace="http://www.tei-c.org/ns/1.0" xmlns:tei="http://www.tei-c.org/ns/1.0"
  exclude-result-prefixes="xsl xs tei #default">
  <xsl:output method="html" encoding="UTF-8" indent="yes"/>

  <xsl:template match="/">
    <div>
<xsl:choose>
        <xsl:when test="//app">There is an app</xsl:when>
        <xsl:otherwise>There is no app</xsl:otherwise>
      </xsl:choose>
    </div>
  </xsl:template>

</xsl:stylesheet>

I apply the XSLT to the XML in PHP with this code:

<?php $XML = new DOMDocument(); 
    $XML->load("une_lecon.xml");
    $_SESSION['strXML'] = $XML->saveXML();
    $xslt = new XSLTProcessor();
    $XSL = new DOMDocument();    
    $XSL->load('une_lecon.xsl', LIBXML_NOCDATA);   
    $xslt->importStylesheet( $XSL );
    $transfo = $xslt->transformToXML($XML);
    echo $transfo;?>

The resulting HTML contains "There is no app" is if there was no element in the XML of which there is actually quite a lot. When I do the same thing in Oxygen with the parser Saxon-PE 11.4 the result contains "There is an app" as expected, so it seems the problem might be specific to PHP. Maybe I am using a wrong namespaces definition?

idchi
  • 761
  • 1
  • 5
  • 15
  • xpath-default-namespace is a 2.0 Attribute, however, your stylesheet version is 1.0. Try getting rid of it. Also, xmlns="http://www.w3.org/1999/xhtml" has no prefix. You may consider whether or not you want it that way. – John Ernst May 09 '23 at 12:30
  • An XSLT 1.0 processor does not support `xpath-default-namespace`. You need to use a prefix if the input nodes are in a namespace (your snippet doesn't show any). See: https://stackoverflow.com/a/34762628/3016153 – michael.hor257k May 09 '23 at 12:31
  • unable to replicate stated problem - this seems to work OK – Professor Abronsius May 09 '23 at 12:35

1 Answers1

1

In your example XML no namespace is defined, so the expression in the XML matches actually. I imagine that the actual XML defines the http://www.tei-c.org/ns/1.0 as the default element namespace. If I add the namespace definition the output is: <div xmlns="http://www.w3.org/1999/xhtml">There is no app</div>.

Xpath 1.0 has no concept of a default namespace, xpath-default-namespace is not available in XSL 1.0. You have to address the elements using a prefix/alias. You XSLT registers the prefix tei for the namespace http://www.tei-c.org/ns/1.0. So you just need to use this in your Xpath expressions //app//tei:app:

<?php

$XML = new DOMDocument();
$XML->loadXML(getXMLString());
$XSL = new DOMDocument();
$XSL->loadXML(getXSLString());

$xslt = new XSLTProcessor();
$xslt->importStylesheet($XSL);
echo $xslt->transformToXML($XML);

function getXMLString() {
// Note: Added namespace definition
return <<<'XML'
<app xmlns="http://www.tei-c.org/ns/1.0">
  <rdg wit="#P1 #P2 #P3"/>
  <rdg wit="#A #B #G #M #V"><app>
      <rdg wit="#B #G #M #V" type="order">Sermo septimus <app>
          <rdg wit="#B #M #V">adhuc</rdg>
          <rdg wit="#G"/>
        </app></rdg>
      <rdg wit="#A" type="order">Septimus adhuc sermo</rdg>
    </app> de nomine <app>
      <rdg wit="#B #G #M #V"/>
      <rdg wit="#A">Jesu</rdg>
    </app> gratioso <app><rdg wit="#B #M #V">propter <app>
          <rdg wit="#M #V">tres</rdg>
          <rdg wit="#B"/>
        </app> virtutes theologicas</rdg>
      <rdg wit="#A #G"/>
    </app></rdg>
</app>
XML;
}

function getXSLString() {
return <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:tei="http://www.tei-c.org/ns/1.0"
  exclude-result-prefixes="xsl xs tei #default">
  
  <xsl:output method="html" encoding="UTF-8" indent="yes"/>

  <xsl:template match="/">
    <div>
      <xsl:choose>
        <xsl:when test="//tei:app">There is an app</xsl:when>
        <xsl:otherwise>There is no app</xsl:otherwise>
      </xsl:choose>
    </div>
  </xsl:template>

</xsl:stylesheet>
XML;
}

Output:

<div xmlns="http://www.w3.org/1999/xhtml">There is an app</div>
ThW
  • 19,120
  • 3
  • 22
  • 44