问题
I am tasked with breaking up an XML document into individual work packages. The only part I am having trouble with is inserting graphic entity declarations in the DOCTYPE like so:
<!DOCTYPE frntcover PUBLIC "-//USA-DOD//DTD TM Assembly REV C" "production.dtd" [
<!ENTITY IMAGE001.jpg SYSTEM "IMAGE001.jpg" NDATA jpg>
]>
(Never mind the extension in the entity name, that's how they do it here.) Anyway, the entities will be constructed from all the @boardno
that are found in the main XML file which could be in a <figure>
or a <graphic>
i.e. <graphic boardno="IMAGE001.jpg"/>
I've been using <xsl:result-document>
to write out the doctype, but I have no idea how to get the entities in there.
I tried LexEv but I get net.sf.saxon.trans.XPathException: Failed to instantiate class com.andrewjwelch.lexev.LexEv (does it have a public zero-argument constructor?)
I contacted Andrew and he said that LexEv is no longer supported and not the tool I need, anyway, since LexEv is for preserving entities and not for writing them to a file.
回答1:
Like Dr. Kay suggested, you could create it by hand using DOE (disable-output-escaping).
Here's something similar to what I've used in the past. What I normally do though is create the entity declarations using Python and then pass them in as a parameter to the stylesheet.
I use an xsl:key so I don't get duplicate declarations.
Also, you could probably refactor how the notational data is determined; especially if the notation is always the same as the file extension.
Example...
XML Input
<frntcover>
<graphic boardno="IMAGE001.jpg"/>
<figure boardno="IMAGE001.jpg"/>
<graphic boardno="IMAGE002.jpg"/>
<graphic boardno="IMAGE003.jpg"/>
</frntcover>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="_gd_gnbrs" match="*[@boardno]" use="@boardno"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:call-template name="generate_doctype">
<xsl:with-param name="root" select="local-name()"/>
<xsl:with-param name="pubid" select="'-//USA-DOD//DTD TM Assembly REV C'"/>
<xsl:with-param name="sysid" select="'production.dtd'"/>
</xsl:call-template>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="generate_doctype">
<xsl:param name="root"/>
<xsl:param name="pubid"/>
<xsl:param name="sysid"/>
<xsl:text disable-output-escaping="yes">
<![CDATA[<!DOCTYPE ]]></xsl:text>
<xsl:value-of select="$root"/>
<xsl:choose>
<xsl:when test="string($pubid)">
<xsl:value-of select="concat(' PUBLIC "',$pubid,'"')" disable-output-escaping="yes"/>
</xsl:when>
<xsl:when test="string($sysid)">
<xsl:text> SYSTEM</xsl:text>
</xsl:when>
</xsl:choose>
<xsl:if test="string($sysid)">
<xsl:value-of select="concat(' "',$sysid,'"')" disable-output-escaping="yes"/>
</xsl:if>
<xsl:text disable-output-escaping="yes"><![CDATA[ []]>
</xsl:text>
<xsl:for-each select="//*[@boardno][count(.|key('_gd_gnbrs',@boardno)[1])=1]">
<xsl:apply-templates select="." mode="ent_decs"/>
</xsl:for-each>
<xsl:text disable-output-escaping="yes"><![CDATA[]>]]>
</xsl:text>
</xsl:template>
<xsl:template match="*" mode="ent_decs">
<xsl:text disable-output-escaping="yes"><![CDATA[<!ENTITY ]]></xsl:text>
<xsl:value-of select="concat(@boardno,' SYSTEM "',@boardno)" disable-output-escaping="yes"/>
<xsl:choose>
<xsl:when test="matches(@boardno,'\.tif','i')">
<xsl:text disable-output-escaping="yes"><![CDATA[" NDATA ccitt4>]]>
</xsl:text>
</xsl:when>
<xsl:when test="matches(@boardno,'\.cgm','i')">
<xsl:text disable-output-escaping="yes"><![CDATA[" NDATA cgm>]]>
</xsl:text>
</xsl:when>
<xsl:when test="matches(@boardno,'\.jpe?g','i')">
<xsl:text disable-output-escaping="yes"><![CDATA[" NDATA jpg>]]>
</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">UNKNOWN GRAPHIC EXTENSION: "<xsl:value-of select="@boardno"/>"</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XML Output
<!DOCTYPE frntcover PUBLIC "-//USA-DOD//DTD TM Assembly REV C" "production.dtd" [
<!ENTITY IMAGE001.jpg SYSTEM "IMAGE001.jpg" NDATA jpg>
<!ENTITY IMAGE002.jpg SYSTEM "IMAGE002.jpg" NDATA jpg>
<!ENTITY IMAGE003.jpg SYSTEM "IMAGE003.jpg" NDATA jpg>
]>
<frntcover>
<graphic boardno="IMAGE001.jpg"/>
<figure boardno="IMAGE001.jpg"/>
<graphic boardno="IMAGE002.jpg"/>
<graphic boardno="IMAGE003.jpg"/>
</frntcover>
Fiddle: http://xsltfiddle.liberty-development.net/gVhDDyQ
回答2:
Saxon does have an extension saxon:doctype
for adding a DTD to the output document: see http://www.saxonica.com/documentation/index.html#!extensions/instructions/doctype
But it requires Saxon-PE or higher.
The only other option is to construct it "by hand" and output it using disable-output-escaping. Or do some post-processing using a "plain text" transformation tool such as Perl or awk.
来源:https://stackoverflow.com/questions/61089009/inserting-entity-declarations-in-doctype-xslt-2-0-saxon9he