我有一个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>因此,在我看来,使用jdom时,not(@qualifier)位似乎无法工作。
我希望了解一下这里发生了什么,以及如何更改样式表,以在我的应用程序中获得与目前通过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中。
发布于 2015-08-25 23:56:34
除了解决原来的问题之外,让我们快速了解一下如何重新组织代码。
您使用了很多//foo表达式。使用//foo启动表达式意味着“在任何级别上搜索整个文档,以查找名称为foo的元素”。除了这是一个潜在的昂贵操作,这通常会产生不必要的副作用,并使您的代码难以阅读,因为它要求您唯一地指定每个元素,从而导致大量重复的代码。
您也使用了大量的xsl:if,但是在XSLT中,几乎没有必要使用if-语句(XSLT1.0和2.0中的一个例外是在处理节点以外的事情时)。在几乎所有的情况下,您都可以用简单的xsl:if替换xsl:apply-templates。
尽管如此,让我们看看如何重写您的代码以获得相同的效果,并且减少出错的机会:
<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元素,则输出<rightsList>。
那你就有:
<xsl:if test="//dspace:field[@mdschema='dc' and @element='rights' and not(@qualifier) and @language='*']">
<rights>它与以下应用模板表达式(假设与其匹配的模板)完全等价:
<xsl:apply-templates select="dspace:field[@mdschema='dc' and @element='rights' and not(@qualifier) and @language='*']" />在这里,我们发现在这个下面,我们有一个几乎等价的表达式,这次是关于not(@language='*')的。那么,让我们看看我们是否能完全消除那些重复的表达式。
首先,让我们回顾一下,看看您在做什么:
<rightsList><rights>rightsUri,将其值设置为找到的第一个<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>几乎每个XSLT1.0处理器都支持exsl:node-set函数,只需将名称空间xmlns:exsl="http://exslt.org/common"添加到xsl:stylesheet声明中即可。
注意,我在select表达式中添加了几次[1]。虽然在代码中没有这样做,但当前代码具有相同的效果,但是如果使用apply-模板,如果遇到多个匹配,则必须指定只对第一个匹配感兴趣。
我认为您的代码可以进一步简化,但我希望确保逻辑保持不变。正如您所看到的,最终的结果是没有任何//。但是,您确实看到了一个/,它现在指向节点集的根,它很方便地只有您感兴趣的节点:那些具有模式"dc“和”right“元素属性的节点,因此我们不必一次又一次地重复该表达式。
您可以尝试这个重写,看看它是否对您当前的错误有帮助,否则我很乐意进一步帮助您。
编辑
编辑之后,原来的上下文项已经是dspace:dim了。如果您不介意总是输出<rightsList> (即使它是空的),您可以简单地用现有的dspace:dim模式替换上面的第一个模板匹配模式。
发布于 2015-08-26 04:16:46
是啊。的确是森林/树木。尽管语言属性在应用程序中的其他地方几乎都被称为" language“(请参见我给出的XML代码段),但在我的样式表所操作的XML中,它实际上被称为"lang”--我最终让步并使用这个答案来确定XML结构是什么。惊喜吧!
无论如何,我在一定程度上遵循了亚伯在他的回答中给出的建议,并对这个特定情况的模板进行了相当程度的简化。我现在刚刚
<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>https://stackoverflow.com/questions/32213625
复制相似问题