PHP使用XSLT处理TEI XML时XPath无法定位元素问题
解决PHP XSLT处理TEI XML时XPath无法匹配元素的问题
问题场景
在PHP中使用XSLT处理包含异文条目的TEI XML文件时,出现XPath无法识别XML元素的问题:XML内存在大量<app>元素,但PHP处理后输出**"There is no app",而在Oxygen中用Saxon-PE 11.4解析时能正常识别<app>元素并输出"There is an app"**。
示例XML片段
<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>
原XSLT模板
<?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>
原PHP处理代码
<?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;?>
问题原因
PHP使用的libxslt是XSLT 1.0的实现,而xpath-default-namespace是XSLT 2.0及以上版本才支持的属性。libxslt会直接忽略这个属性,导致XPath查询的是无命名空间的<app>元素,但实际TEI XML的元素都属于http://www.tei-c.org/ns/1.0命名空间(完整TEI文件的根元素会声明该命名空间),因此匹配失败。
解决方案
由于XSLT 1.0不支持默认命名空间的XPath查询,需要改用命名空间前缀来明确引用目标元素:
修改后的XSLT模板
<?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"> <xsl:output method="html" encoding="UTF-8" indent="yes"/> <xsl:template match="/"> <div> <xsl:choose> <!-- 使用tei前缀匹配命名空间下的app元素 --> <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>
额外注意事项
确保你的TEI XML根元素正确声明了TEI命名空间,例如:
<TEI xmlns="http://www.tei-c.org/ns/1.0"> <!-- 其他内容 --> </TEI>
这样XML中的<app>等元素才会被归入http://www.tei-c.org/ns/1.0命名空间,XPath中的tei:app才能正确匹配。
内容的提问来源于stack exchange,提问作者Pavel Třiska
相关产品推荐
相关产品推荐

