从XSLT引用XML文档类型实体

时间:2018-07-31 01:16:48

标签: xml xslt

使用XSL文件将XML转换为HTML时,我试图访问XML文件的!ENTITY声明中的!DOCTYPE元素。在XML中,我有一个widget元素,它具有一个与!ENTITY名称相对应的属性,并且我希望XSLT将其转换为!ENTITY的值。

XML文件

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE root[
  <!ENTITY Widget_Manual "Widget_Manual_File_Name.pdf" >
]>

<root>
  <!-- I want to convert this to "Widget_Manual_File_Name.pdf" in the transform -->
  <widget entityIdent="Widget_Manual" />
</root>

XSLT文件

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="/">
    <html>
      <head />
      <body>
        <xsl:apply-templates />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="widget">
    <!-- Embed PDF -->
    <object width="800" height="600" type="application/pdf">
      <xsl:attribute name="data">
        <!-- How do I access the !ENTITY's value using the @entityIdent attribute? -->
        <xsl:value-of select="@entityIdent" />
      </xsl:attribute>
    </object>
  </xsl:template>

</xsl:stylesheet>

实际输出

<object width="800" height="600" type="application/pdf" data="Widget_Manual"></object>

所需的输出

<object width="800" height="600" type="application/pdf" data="Widget_Manual_File_Name.pdf"></object>

1 个答案:

答案 0 :(得分:1)

最好只在XML中使用一个实体,以便XML解析器在解析文档时会为您扩展该实体。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
  <!ENTITY Widget_Manual "Widget_Manual_File_Name.pdf" >
]>
<root>
    <!-- I want to convert this to "Widget_Manual_File_Name.pdf" in the transform -->
    <widget entityIdent="&Widget_Manual;" />
</root>

如果您没有XML的控制权,但想在XSLT中执行查找/替换,那么您将不得不跳过一些麻烦。 XSLT对已经解析的XML进行操作,并且DTD内容不能在XML信息集中直接寻址。

但是,您可以获得base-uri(),然后使用unparsed-text()来读取XML作为字符串,然后将replace()与具有捕获组(或子字符串函数)的正则表达式一起使用)以获取ENTITY的值。

可以使用以下XSLT 2.0样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes" />
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@entityIdent">
        <xsl:attribute name="{name()}">
            <xsl:value-of select="replace(
                                   unparsed-text(base-uri()), 
                                   concat('.*!ENTITY ', ., ' &quot;(.+?)&quot;.*'),
                                   '$1', 
                                   's')"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>