避免与XSLT / XPath重复的属性名称 [英] Avoid duplicated attributes names with XSLT/ XPath

查看:209
本文介绍了避免与XSLT / XPath重复的属性名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有一个这样的XML:

 < parole> 
< parola id =a> 1< / parola>
< parola id =b> 2< / parola>
< parola id =c> 3< / parola>
< parola id =a> 4< / parola>
< parola id =a> 5< / parola>
< parola id =b> 6< / parola>
< / parole>

现在,我知道 generate-id()函数存在。但是,为了学习的目的,我想知道如何使用XSLT改变名为id的属性值。



我已经想到了一个算法像:


考虑以下内容和上一个属性的兄弟。

如果您遇到现在的属性,在这个名字的末尾添加f,并递归地添加另一个f,直到我们没有更多的属性值相同。


所以我的最终XML将如下所示:

 < parole> 
< parola id =a> 1< / parola>
< parola id =b> 2< / parola>
< parola id =c> 3< / parola>
< parola id =af> 4< / parola>
< parola id =aff> 5< / parola>
< parola id =bf> 6< / parola>
< / parole>

现在,我试图用一个递归函数来获得这个结果,如:

 < xsl:variable name =following-siblings-idsselect =/ parole / parola / following-sibling :: parola / @ id /> 
< xsl:variable name =previous-siblings-idsselect =/ parole / parola / prior-sibling :: parola / @ id/>

< xsl:function name =du:checkas =xs:string>
< xsl:param name =id/>
< xsl:choose>
< xsl:when test =$ id = $ following-siblings-id and $ previous-siblings-id>
< xsl:value-of select =du:check(concat($ id,'f'))/>
< / xsl:when>
< xsl:否则>
< xsl:value-of select =$ id/>
< / xsl:否则>
< / xsl:choose>
< / xsl:function>

< xsl:template match =parola>
< xsl:value-of select =du:check(@id)/>
< / xsl:template match =parola>

但是我得到的结果如


afbfcfafafbf


所需的一个。



任何提示?这将是非声明性语言的一个简单的任务,动态变量和 for-each s,但我不知道如何在XSLT ...

解决方案

这是一个XSLT 1解决方案。以下转换

 < xsl:stylesheet 
version =1.0xmlns:xsl =http:// www.w3.org/1999/XSL/Transform\">

<! - 标准复印模板 - >
< xsl:template match =node()| @ *>
< xsl:copy>
< xsl:apply-templates select =node()| @ */>
< / xsl:copy>
< / xsl:template>

< xsl:template name =make-f>
< xsl:param name =n/>
< xsl:if test =$ n> 0> f< xsl:call-template name =make-f>
< xsl:with-param name =nselect =$ n - 1/>< / xsl:call-template>
< / xsl:if>
< / xsl:template>

< xsl:template match =parola / @ id>
< xsl:variable name =idselect =。/>
< xsl:variable name =f>
< xsl:call-template name =make-f>
< xsl:with-param name =nselect =count(../ previous-sibling :: parola / @ id [。= $ id])/>
< / xsl:call-template>
< / xsl:variable>
< xsl:attribute name =id>
< xsl:value-of select =concat(。,$ f)/>
< / xsl:attribute>
< / xsl:template>

< / xsl:stylesheet>

当应用于您的输入样本时,会生成以下输出:

  $ xsltproc test.xsl test.xml 
<?xml version =1.0?>
<假释>
< parola id =a> 1< / parola>
< parola id =b> 2< / parola>
< parola id =c> 3< / parola>
< parola id =af> 4< / parola>
< parola id =aff> 5< / parola>
< parola id =bf> 6< / parola>
< / parole>


Say I have an XML like that:

<parole>
   <parola id="a">1</parola>
   <parola id="b">2</parola>
   <parola id="c">3</parola>
   <parola id="a">4</parola>
   <parola id="a">5</parola>
   <parola id="b">6</parola>
</parole>

Now, I know that the generate-id() function exists. But, for a learning purpose, I would like to know how to change with XSLT the values of the attributes called "id".

I've thought about an "algorithm" like:

consider the following and the preceding sibling of an attribute.
If you meet a duplicate of the present attribute, add "f" to the end of this name and (recursively) add another "f" until we have no more attributes with the same value.

So my final XML would be like:

<parole>
  <parola id="a">1</parola>
  <parola id="b">2</parola>
  <parola id="c">3</parola>
  <parola id="af">4</parola>
  <parola id="aff">5</parola>
  <parola id="bf">6</parola>
</parole>

Now, I've tried to get this result with a recursive function like:

<xsl:variable name="following-siblings-ids" select="/parole/parola/following-sibling::parola/@id"/>
<xsl:variable name="preceding-siblings-ids" select="/parole/parola/preceding-sibling::parola/@id"/>

<xsl:function name="du:check" as="xs:string">
    <xsl:param name="id" /> 
    <xsl:choose>
        <xsl:when test="$id  = $following-siblings-ids and $preceding-siblings-ids">
            <xsl:value-of select="du:check(concat($id, 'f'))"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$id"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:function>

<xsl:template match="parola">
  <xsl:value-of select="du:check(@id)"/>
</xsl:template match="parola">

But I get a result like

"af" "bf" "cf" "af" "af" "bf"

instead of the the desired one.

Any hints? This would be a simple task in a non-declarative language with dynamic variables and for-eachs, but I don't know how to realize it in XSLT...

解决方案

Here is an XSLT 1 solution. The following transformation

<xsl:stylesheet
    version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

  <xsl:template name="make-f">
    <xsl:param name="n"/>
    <xsl:if test="$n > 0">f<xsl:call-template name="make-f">
    <xsl:with-param name="n" select="$n - 1"/></xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template match="parola/@id">
    <xsl:variable name="id" select="."/>
    <xsl:variable name="f">
      <xsl:call-template name="make-f">
    <xsl:with-param name="n" select="count(../preceding-sibling::parola/@id[.=$id])"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:attribute name="id">
      <xsl:value-of select="concat(., $f)"/>
    </xsl:attribute>
  </xsl:template>

</xsl:stylesheet>

when applied to your input sample, produces the following output:

$ xsltproc test.xsl test.xml
<?xml version="1.0"?>
<parole>
  <parola id="a">1</parola>
  <parola id="b">2</parola>
  <parola id="c">3</parola>
  <parola id="af">4</parola>
  <parola id="aff">5</parola>
  <parola id="bf">6</parola>
</parole>

这篇关于避免与XSLT / XPath重复的属性名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆