not(@attribute)测试在JDom XSL转换中不起作用



我有一个XSLT样式表,使用xsltproc可以像预期的那样工作,但在我的实际应用程序中产生不同的输出,其中转换是通过org.jdom.transform.XSLTransformer (jdom 1.0)应用的,我相信使用的是Xalan。

样式表片段(这是一个更大的模板的一部分,开头如下:<xsl:template match="/dspace:dim[@dspaceType='ITEM']">):

<xsl:if test="//dspace:field[@mdschema='dc' and @element='rights']">
  <rightsList>
    <xsl:if test="//dspace:field[@mdschema='dc' and @element='rights' and not(@qualifier) and @language='*']">
      <rights>
        <xsl:if test="//dspace:field[@mdschema='dc' and @element='rights' and @qualifier='uri' and @language='*']">
          <xsl:attribute name="rightsUri">
            <xsl:value-of select="//dspace:field[@mdschema='dc' and @element='rights' and @qualifier='uri' and @language='*']"/>
          </xsl:attribute>
        </xsl:if>
        <xsl:value-of select="//dspace:field[@mdschema='dc' and @element='rights' and not(@qualifier) and @language='*']" />
      </rights>
    </xsl:if>
    <xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='rights' and not(@language='*')]" />
  </rightsList>
</xsl:if>

<xsl:template match="//dspace:field[@mdschema='dc' and @element='rights' and not(@language='*')]">
    <rights><xsl:value-of select="." /></rights>
</xsl:template>

XML代码片段:

<dim:dim dspaceType="ITEM" xmlns:dim="http://www.dspace.org/xmlns/dspace/dim">
  <dim:field element="rights" language="en_NZ" mdschema="dc">Actual text redacted</dim:field>
  <dim:field element="rights" language="*" mdschema="dc">Attribution 3.0 New Zealand</dim:field>
  <dim:field element="rights" qualifier="uri" language="*" mdschema="dc">http://creativecommons.org/licenses/by/3.0/nz/</dim:field>
</dim:dim>
使用xsltproc,这将生成

<rightsList>
  <rights rightsUri="http://creativecommons.org/licenses/by/3.0/nz/">Attribution 3.0 New Zealand</rights>
  <rights>Actual text redacted</rights>
</rightsList>

在我的应用程序中,这产生

<rightsList>
  <rights>Actual text redacted</rights>
  <rights>Attribution 3.0 New Zealand</rights>
  <rights>http://creativecommons.org/licenses/by/3.0/nz/</rights>
</rightsList>

所以对我来说,看起来not(@qualifier)位不工作使用jdom。

我希望了解这里发生了什么,以及如何更改样式表以在我的应用程序中获得与我目前通过xsltproc获得的相同的结果。

编辑后添加:以防万一,样式表以 开头
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:dspace="http://www.dspace.org/xmlns/dspace/dim"
            xmlns:exslt="http://exslt.org/common"
            xmlns="http://datacite.org/schema/kernel-3"
            extension-element-prefixes="exslt"
            exclude-result-prefixes="exslt"
            version="1.0">

,也包括这个模板:

<!-- Don't copy everything by default! -->
<xsl:template match="@* | text()" />

请参阅下面我的回答 XML结构实际上与我认为的不同,因此问题根本不在XSL中。

除了解决最初的问题之外,让我们快速了解一下如何重新组织代码。

你用了很多//foo表达式。以//foo开头的表达式意味着"在任何级别搜索整个文档,查找名称为foo的元素"。除了这是一个潜在的昂贵的操作,这通常有不必要的副作用,并使您的代码难以阅读,因为它要求您唯一地指定每个元素,导致大量重复的代码。

您还使用了大量的xsl:if,但是在XSLT中,几乎没有必要使用if语句(XSLT 1.0和2.0中的一个例外是当您处理节点以外的东西时)。在几乎所有情况下,您都可以用简单的xsl:apply-templates替换xsl:if

也就是说,让我们看看如何重写代码以获得相同的效果并减少出错的机会:

<xsl:if test="//dspace:field[@mdschema='dc' and @element='rights']">
    <rightsList>
      .....

类似于具有如下匹配模板(假设您有一个用于不感兴趣的节点的一次性模板):

<xsl:template match="dspace:dim[dspace:field[@mdschema='dc' and @element='rights']]">
    <rightsList>

这就是说:如果你遇到一个dim元素和任何一个field元素都设置了这些属性,那么输出<rightsList>

那么你有:

<xsl:if test="//dspace:field[@mdschema='dc' and @element='rights' and not(@qualifier) and @language='*']">
    <rights>

与下面的apply-template表达式完全等价(假设有一个与之匹配的模板):

<xsl:apply-templates select="dspace:field[@mdschema='dc' and @element='rights' and not(@qualifier) and @language='*']" />

在这里,我们发现稍微低于那一点,我们有一个几乎相等的表达式,这次是not(@language='*')。那么,让我们看看能否把这些重复的表达式都去掉。

首先,让我们回顾一下,看看你在做什么:

  • 如果任何地方有"dc"one_answers"rights",那么创建一个<rightsList>
  • 如果这些没有限定符但有语言"*",创建<rights>
  • 在这里面,创建一个属性rightsUri,如果任何地方任何限定符有值"uri"和语言"*",将其值设置为第一个这样你找到
  • <rights>元素之后(当前结构中最多只能有一个),为每个字段元素创建一个<rights>列表,语言为"*"

如果这是正确的,那么可以重写如下:

<xsl:template match="dspace:dim[dspace:field[@mdschema='dc' and @element='rights']]">
    <xsl:variable name="adjusted">
        <xsl:copy-of select="dspace:field[@mdschema='dc' and @element='rights']"/>
    </xsl:variable>
    <rightsList>
        <xsl:apply-templates select="exsl:node-set($adjusted)/*[not(@qualifier) and @language='*'][1]" mode="noquali"/>
        <xsl:apply-templates select="exsl:node-set($adjusted)/*[not(@language='*')]" />
    </rightsList>
</xsl:template>
<xsl:template match="dspace:field" mode="noquali">
    <rights>
        <xsl:apply-templates select="/dspace:field[@qualifier='uri' and @language='*'][1]" mode="uri"/>
        <xsl:value-of select="."/>
    </rights>
</xsl:template>
<xsl:template match="dspace:field" mode="uri">
    <xsl:attribute name="rightsUri" select="." />
</xsl:template>
<!-- matching anything else -->
<xsl:template match="dspace:field">
    <rights><xsl:value-of select="." /></rights>
</xsl:template>

几乎每个XSLT 1.0处理器都支持exsl:node-set函数,只需将名称空间xmlns:exsl="http://exslt.org/common"添加到xsl:stylesheet声明中。

注意,我在选择表达式中添加了几次[1]。虽然您没有在代码中这样做,但您当前的代码具有相同的效果,但是如果您使用apply-templates,如果遇到多个匹配,则必须指定仅对第一个匹配感兴趣。

我认为你的代码可以进一步简化,但我想确保逻辑保持完全相同。正如您所看到的,最终结果是没有任何//。但是,您确实看到了一个/,它现在指向节点集的根,方便地只包含您感兴趣的节点:具有模式"dc"one_answers"rights"元素属性的节点,因此我们不必一遍又一遍地重复该表达式。

您可以尝试重写,看看它是否有助于解决您当前的错误,否则我很乐意进一步帮助您。

编辑

编辑后,您的原始上下文项将已经是dspace:dim。如果您不介意总是输出<rightsList>(即使它最终为空),您可以简单地将上面的第一个模板匹配模式替换为现有的dspace:dim模式。

废话。森林和树木。尽管语言属性在应用程序的其他地方几乎都被称为"语言"(参见我给出的XML片段),但在样式表所操作的XML中,它实际上被称为"lang"——我最终屈服了,并使用这个答案来确定XML结构是什么。惊喜!

无论如何,我遵循了Abel在他的部分回答中给出的建议,并为这个特殊情况简化了模板。现在只有

<xsl:if test="dspace:field[@mdschema='dc' and @element='rights']">
    <rightsList>
        <xsl:apply-templates select="dspace:field[@mdschema='dc' and @element='rights']"/>
    </rightsList>
</xsl:if>
大模板中的

,加上几个自定义的

:
<xsl:template match="dspace:field[@mdschema='dc' and @element='rights']">
    <xsl:choose>
        <xsl:when test="@qualifier='uri'"/>
        <xsl:otherwise>
            <rights>
                <xsl:if test="@lang='*'">
                    <xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='rights' and @qualifier='uri' and @lang='*'][1]" mode="rightsURI"/>
                </xsl:if>
                <xsl:value-of select="."/>
            </rights>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template match="dspace:field[@mdschema='dc' and @element='rights' and @qualifier='uri' and @lang='*']" mode="rightsURI">
    <xsl:attribute name="rightsURI"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>

相关内容

  • 没有找到相关文章

最新更新