XSL更新seg的xml:id属性时position()取值异常问题求助
解决XSLT中
position()始终返回1的问题 你的问题核心在于对XSLT模板上下文和position()函数的理解偏差,还有变量定义的小错误,咱们一步步来修正:
1. 先修正变量定义的语法错误
你写的<xsl:variable name="var_val" select="tei:document/n@"/>是语法错误,正确的写法应该是获取document元素的n属性,比如:
<xsl:variable name="doc-n" select="/tei:document/@n"/>
这里用绝对路径/tei:document确保能精准定位到根节点的n属性,变量名也更直观好懂。
2. 为什么position()总是返回1?
你的模板匹配的是tei:seg/@xml:id属性节点,当处理每个属性时,当前上下文是单个属性节点——也就是说,每次模板只处理一个属性,这个属性在自己的上下文序列里排第1,所以position()自然返回1。你需要的是seg元素在同级兄弟中的位置,就得基于seg的上下文来计算,而非属性的上下文。
解决方案1:匹配seg元素而非属性(更推荐)
直接匹配tei:seg元素,在输出时重新生成xml:id属性,这样position()就能正确返回当前seg在同级兄弟中的位置:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tei="http://example.com/tei"> <xsl:output method="xml" indent="yes"/> <!-- 默认模板:复制所有未被自定义模板匹配的节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:variable name="doc-n" select="/tei:document/@n"/> <!-- 自定义seg模板,重新生成xml:id --> <xsl:template match="tei:seg"> <seg xml:id="{$doc-n}-{position()}"> <!-- 复制seg的其他属性和子节点,排除原xml:id --> <xsl:apply-templates select="@*[not(local-name()='xml:id')]|node()"/> </seg> </xsl:template> </xsl:stylesheet>
这里的核心逻辑:
- 默认模板负责保留文档的其他结构,只修改
seg的xml:id - 在
seg的模板中,position()的上下文是所有同级的seg元素,所以能正确返回1、2、3、4...
解决方案2:在属性模板中手动计算位置
如果你坚持要匹配属性节点,可以通过统计当前seg的前置兄弟seg数量来得到位置:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tei="http://example.com/tei"> <xsl:output method="xml" indent="yes"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:variable name="doc-n" select="/tei:document/@n"/> <xsl:template match="tei:seg/@xml:id"> <xsl:attribute name="xml:id"> <xsl:value-of select="$doc-n"/> <xsl:text>-</xsl:text> <!-- 统计当前seg前面有多少个同级seg,加1就是它的位置 --> <xsl:value-of select="count(parent::tei:seg/preceding-sibling::tei:seg) + 1"/> </xsl:attribute> </xsl:template> </xsl:stylesheet>
验证结果
两种方案运行后,都会生成你预期的结果:
<document n="foo" xmlns="http://example.com/tei"> <body> <seg xml:id="foo-1">some text</seg> <seg xml:id="foo-2">some text</seg> <seg xml:id="foo-3">some text</seg> <seg xml:id="foo-4">some text</seg> </body> </document>
内容的提问来源于stack exchange,提问作者jbrehr
相关产品推荐
相关产品推荐

