xslt:无上下文的“生成 id”?

问题描述 投票:0回答:2

据我了解,xslt 函数

generate-id()
将根据
node
及其上下文(祖先)返回唯一的 id。

有没有办法获得一个仅依赖于

node
(及其子节点)的id,而不是它在文档中的位置?

使用

xinclude
时,相同的节点可以放入多个位置 - 因此会生成两个不同的 id。如何创建一个字母数字字符串,该字符串对于通过
xinclude
插入到文档中的节点集的每个实例都相同?

所以我有一个文件

node.xml
:

<?xml version="1.0" encoding="utf-8"?>
<node name="joe"/>

还有一个

document.xml

<?xml version="1.0" encoding="utf-8"?>
<document xmlns:xi="http://www.w3.org/2003/XInclude">
    <container name="first">
        <xi:include href="node.xml"/>
    </container>
    <container name="second">
        <xi:include href="node.xml"/>
    </container>
</document>

还有一个

process.xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="container">
this will not be identical for different matches of the template, although the matched <node/> has the same content: '<xsl:value-of select="generate-id(node)"/>'
appending some attributes this is too simple, there might be differences deeper down the hierarchy, which should resolve in a different id: '<xsl:value-of select="node/@name"/>'
</xsl:template>
</xsl:stylesheet>

使用

xsltproc --xinclude process.xslt document.xml
进行处理。对于两次出现的
<node/>
,我需要相同的 id/字符串,因为它们是相同的。

问候

啊。 这个看起来非常相似。但是,我不想手动连接值...?在我的情况下,它不容易扩展...也许我可以使用

number()
解决一些问题,但感觉应该有更自动的东西...

ps:使用 xsltproc,所以不要花哨......;-)

xml xslt-1.0
2个回答
1
投票

两个节点元素不相同。他们有相同的孩子/属性/后代,但他们有不同的父母和不同的兄弟姐妹。

根据 Deep-equal 函数的 XPath 2.0 定义,这两个节点元素可能是深度相等的。但深度相等规范绝不是指定函数的唯一可能方式:阅读规范,您将看到可以以不同方式定义任意数量的规则。 (例如,对命名空间前缀、纯空白文本节点、范围内命名空间、基本 URI、类型注释的依赖)。

考虑到这些警告,在某些情况下,让一个函数说

fingerprint(node)
使得
fingerprint(N) = fingerprint(M)
当且仅当
deep-equal(N, M)
是有用的。你可以编写自己的函数,但它一点也不容易编写,而且可能效率不高。

因此,了解为什么您认为需要它会有所帮助,因为可能有更简单的方法来解决您的问题。


0
投票

考虑以下样式表:

XSLT 1.0

answer-stylesheet.xsl

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xi="http://www.w3.org/2003/XInclude">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="xi:include">
    <xsl:variable name="node" select="document(@href)/*" />
    <included>
        <id>
            <xsl:value-of select="generate-id($node)"/>
        </id>
        <name>
            <xsl:value-of select="$node/@name"/>
        </name>
    </included>
</xsl:template>

</xsl:stylesheet>

当这应用于您的输入示例时 - 无需激活

--xinclude
选项...

xsltproc answer-stylesheet.xsl document.xml

...结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<document xmlns:xi="http://www.w3.org/2003/XInclude">
  <container name="first">
    <included>
      <id>idp944</id>
      <name>joe</name>
    </included>
  </container>
  <container name="second">
    <included>
      <id>idp944</id>
      <name>joe</name>
    </included>
  </container>
</document>

我相信您现在尝试的方式 - 首先执行

xinclude
- 导致 XSLT 接收合并文档,其中每个包含实例都转换为单独的节点集 - 并且处理器无法知道这些节点- 过去是一套。

© www.soinside.com 2019 - 2024. All rights reserved.