检查 xsl:attribute 名称是否对 XSL-FO 有效

Check if xsl:attribute name is valid for XSL-FO

在我的数据中,可能有一个或多个处理指令用于为特定内容块提供新属性或覆盖现有属性的值。

我这样做的方式要求 PI 的名称是有效的 xsl 属性名称。

问题:是否可以在 xsl-stylesheet 中检查 PI 的名称是否是实际有效的(=允许作为 XSL-FO 中的 <xsl:attribute name="*thisname*">)属性名称?

<xsl:if test="./processing-instruction()"> <!-- add condition to test for valid name? -->
    <xsl:for-each select="./processing-instruction()">
        <xsl:variable name="pi_name"><xsl:value-of select="local-name()" /></xsl:variable>
        <xsl:attribute name="{$pi_name}"><xsl:value-of select="." /></xsl:attribute>
    </xsl:for-each>
</xsl:if>

编辑:

关于这个问题:

这是我使用的源自 Tony 解决方案的代码:

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

    <xsl:template name="handle_block_attribute">
        <xsl:variable name="attributes" select="document('PATH\attributelist.xml')//attributelist/attribute"/>

        <xsl:if test=".//processing-instruction()">
            <xsl:for-each select=".//processing-instruction()">
                <xsl:variable name="pi_name"><xsl:value-of select="local-name()" /></xsl:variable>
                <xsl:choose>
                    <xsl:when test="$pi_name = $attributes">
                        <xsl:attribute name="{$pi_name}">
                            <xsl:value-of select="." />
                        </xsl:attribute>
                    </xsl:when>
                    <xsl:otherwise>
                        <fo:inline color="red">Invalid attribute-name in PI: <xsl:value-of select="$pi_name" /></fo:inline><fo:block />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </xsl:if>

    </xsl:template>
</xsl:stylesheet>

模板是这样调用的:

<xsl:template match="para">
    <fo:block xsl:use-attribute-sets="para.standard">
        <xsl:call-template name="handle_block_attribute" />
        <xsl:apply-templates/>
    </fo:block>
</xsl:template>

这就是数据:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book>
    <sect class="hierarchic" type="chapter">
        <para class="heading" style="Chapter">
            <inline style="HeadingText">HD</inline>
        </para>
        <para style="Standard">Lorem ipsum dolor sit amet consectetuer eleifend consequat pede Aenean est. <?font-size 13pt?><?fotn-family Arial?><?color green?><?fline-height 3pt?></para>
        <para style="Standard">Consequat semper tortor id convallis leo Phasellus eget non sagittis neque.</para>
    </sect>
</book>

编辑2:

好吧,也许有更优雅的方法,但它有效:我将使用两个 for-each-loops,一个用于正确的 PI,另一个用于有缺陷的 PI,包括错误输出。

<xsl:if test=".//processing-instruction()">
    <xsl:for-each select=".//processing-instruction()">
        <xsl:variable name="pi_name"><xsl:value-of select="local-name()" /></xsl:variable>
        <xsl:if test="$pi_name = $attributes">
            <xsl:attribute name="{$pi_name}">
                <xsl:value-of select="." />
            </xsl:attribute>
        </xsl:if>
    </xsl:for-each>
    <xsl:for-each select=".//processing-instruction()">
        <xsl:variable name="pi_name"><xsl:value-of select="local-name()" /></xsl:variable>
        <xsl:if test="not($pi_name = $attributes)">
            <fo:inline color="red">Invalid attribute name in PI: <xsl:value-of select="$pi_name" /></fo:inline><fo:block />
        </xsl:if>
    </xsl:for-each>
</xsl:if>

因为 Martin Honnen , PI target and attributes names must conform the Name production of XML specification。因此,唯一可能发生冲突的情况是 PI 目标可能被解释为 QName 并且前缀与范围内命名空间绑定不匹配。

因此,PI 目标中不允许 :

下面是不同XSLT处理器在解析输入源时给出的错误:

<?a:b 7pt?>
<root/>  

撒克逊人:

org.xml.sax.SAXParseException; systemId: urn:from-string; lineNumber: 1; columnNumber: 6; A colon is not allowed in the name 'a:b' when namespaces are enabled.

MSXML:

Input parsing error: Entity names, PI targets, notation names and attribute values declared to be of types ID, IDREF(S), ENTITY(IES) or NOTATION cannot contain any colons. , 1:7, <?a:b 7pt?>

编辑:关于 <?fotn-size 7pt?>,此样式表遵循您的示例

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <root>
            <xsl:if test="./processing-instruction()">
                <xsl:for-each select="./processing-instruction()">
                    <xsl:variable name="pi_name">
                        <xsl:value-of select="local-name()" />
                    </xsl:variable>
                    <xsl:attribute name="{$pi_name}">
                        <xsl:value-of select="." />
                    </xsl:attribute>
                </xsl:for-each>
            </xsl:if>
        </root>
    </xsl:template>
  </xsl:stylesheet>

有了这个输入:

<?fotn-size 7pt?>
<root/>

输出:

<root fotn-size="7pt"/>

您使用 XSLT 1.0 而不是 XSLT 2.0 或 XSLT 3.0 使它变得比您自己需要的更难了,这仅仅是因为构建一个 属性 名称列表来进行比较变得更加困难。使用更高版本,您可以制作一系列字符串。对于 XSLT 1.0,最简单的方法(我记得)是将每个 属性 名称作为单独元素的值,然后将预期的 属性 名称与选定的元素集进行比较。 XPath 的 = 的神奇之处在于,如果一侧的任何值与另一侧的任何值匹配,则为真。

您可以通过处理 XSL 规范的 XML 源来提取 XSL-FO 属性 名称的最终列表:http://www.w3.org/TR/2006/REC-xsl11-20061205/xslspec.xml

使用此样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0"
    xmlns:fo="http://www.w3.org/1999/XSL/Format"
    xmlns:local="uuid:503f6e96-fda1-4464-98b6-a60dbecc5946"
    exclude-result-prefixes="local">

    <properties xmlns="uuid:503f6e96-fda1-4464-98b6-a60dbecc5946">
        <property>font-size</property>
        <property>font-weight</property>
    </properties>

    <xsl:variable name="properties" select="document('')/*/local:properties/local:property"/>
    <xsl:template match="fo:*">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:for-each select="processing-instruction()">
                <xsl:variable name="pi_name" select="local-name()" />
                <xsl:choose>
                    <xsl:when test="$pi_name = $properties">
                        <xsl:attribute name="{$pi_name}">
                            <xsl:value-of select="." />
                        </xsl:attribute>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:message>Unrecognised property: <xsl:value-of select="$pi_name"
                             /></xsl:message>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

此文档:

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <fo:block><?font-size 16pt?><?font-weight bold?></fo:block>
    <fo:block><?fotn-size 16pt?><?bogus bold?></fo:block>
</fo:root>

生成这个:

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:block font-size="16pt" font-weight="bold"/>
  <fo:block/>
</fo:root>

还有关于 'fotn-size' 和 'bogus' 的消息。

我将 属性 名称放在样式表中以便于测试。您可以将 XML 放在外部文档中,而不必对 local 命名空间大惊小怪。命名空间是必需的,因为 XSLT 样式表顶层允许的唯一非 XSLT 元素必须位于非 XSLT 命名空间中。