仅当源属性存在时,XSLT 才向节点添加属性

发布于 2024-11-05 11:25:41 字数 1515 浏览 0 评论 0原文

我的意思是,当且仅当该属性的数据源存在时,才将属性元素添加到节点。

换句话说,我不想最终得到空属性,以防源与我的规则不匹配。

<tok id="t1" fooID=""/> //not accepted
<tok id="t1" /> //instead of ^
<tok id="t1" fooID="bar"/> //accepted


Moreover, I would like to test if the source has more than 1 node corresponding to my current attribute, and if so, add another foo attribute with "source2". Here's what I'm currently using:

<xsl:template match="tokens/token">
<tok id="{@ID}" 
     ctag="{/root/myStuff/fooSources[1and2 how?]/fooSource[@fooID=current()/@ID]}" 
>
</tok>

源 XML 是这样的:

<root>
   <myStuff>
      <tokens>
         <token ID="bar"/>
         <token ID="anotherBar"/>
         <token ID="noFoo"/>
      </tokens>

      <fooSources>
         <fooSource fooID="bar"> kitten </fooSource>
         <fooSource fooID="anotherBar"> shovel </fooSource>
      </fooSources>

      <fooSources>
         <fooSource fooID="bar"> kitty </fooSource>
         <fooSource fooID="notAnotherBar"> fridge </fooSource>
      </fooSources>
   </myStuff>
</root>

期望的结果是这样的:

<tok id="bar" fooID="kitten" fooID_2="kitty"/>
<tok id="anotherBar" fooID="shovel"/> 
<tok id="noFoo" /> 

提前感谢您的帮助!

PS:我想在 xpath 1.0 中执行此操作

I mean to add an attribute element to a node if and only if the source for that attribute's data exists.

In other words, I don't want to end up with empty attributes in case the source isn't matched by my rule.

<tok id="t1" fooID=""/> //not accepted
<tok id="t1" /> //instead of ^
<tok id="t1" fooID="bar"/> //accepted


Moreover, I would like to test if the source has more than 1 node corresponding to my current attribute, and if so, add another foo attribute with "source2". Here's what I'm currently using:

<xsl:template match="tokens/token">
<tok id="{@ID}" 
     ctag="{/root/myStuff/fooSources[1and2 how?]/fooSource[@fooID=current()/@ID]}" 
>
</tok>

The source XML is like this:

<root>
   <myStuff>
      <tokens>
         <token ID="bar"/>
         <token ID="anotherBar"/>
         <token ID="noFoo"/>
      </tokens>

      <fooSources>
         <fooSource fooID="bar"> kitten </fooSource>
         <fooSource fooID="anotherBar"> shovel </fooSource>
      </fooSources>

      <fooSources>
         <fooSource fooID="bar"> kitty </fooSource>
         <fooSource fooID="notAnotherBar"> fridge </fooSource>
      </fooSources>
   </myStuff>
</root>

The desired result would be this:

<tok id="bar" fooID="kitten" fooID_2="kitty"/>
<tok id="anotherBar" fooID="shovel"/> 
<tok id="noFoo" /> 

Thanks in advance for any help!

PS: I'd like to do this in xpath 1.0

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一杯敬自由 2024-11-12 11:25:41
<foo>
   <xsl:if test="@bar">
      <xsl:attribute name="id">
         <xsl:value-of select="@bar"/>
      </xsl:attribute>
   </xsl:if>
</foo>
<foo>
   <xsl:if test="@bar">
      <xsl:attribute name="id">
         <xsl:value-of select="@bar"/>
      </xsl:attribute>
   </xsl:if>
</foo>
我还不会笑 2024-11-12 11:25:41

PS:我想在 xpath 1.0 中执行此操作

XPath 是 XML 文档的查询语言,因此它不能修改文档的任何节点。

产生想要的结果(更改元素名称并添加元素的新属性)您必须使用另一种托管 XPath 的语言。最合适的此类语言是 XSLT,它是专门为用于 XML 转换而创建的。

此 XSLT 1.0 转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kFooIdByVal" match="fooSource/@fooID"
  use="."/>

 <xsl:template match="token">
  <tok>
   <xsl:copy-of select="@*"/>
   <xsl:apply-templates
        select="key('kFooIdByVal',@ID)"/>
  </tok>
 </xsl:template>

 <xsl:template match="@fooID">
  <xsl:variable name="vattrName"
   select="concat('fooID',
                  substring(concat('_',position()),
                            1 div (position() >1)
                           )
                  )
   "/>

  <xsl:attribute name="{$vattrName}">
   <xsl:value-of select="normalize-space(..)"/>
  </xsl:attribute>
 </xsl:template>
 <xsl:template match="fooSources"/>
</xsl:stylesheet>

应用于提供的 XML 文档时

<root>
    <myStuff>
        <tokens>
            <token ID="bar"/>
            <token ID="anotherBar"/>
            <token ID="noFoo"/>
        </tokens>
        <fooSources>
            <fooSource fooID="bar"> kitten </fooSource>
            <fooSource fooID="anotherBar"> shovel </fooSource>
        </fooSources>
        <fooSources>
            <fooSource fooID="bar"> kitty </fooSource>
            <fooSource fooID="notAnotherBar"> fridge </fooSource>
        </fooSources>
    </myStuff>
</root>

产生所需的正确结果

<tok ID="bar" fooID="kitten" fooID_2="kitty"/>
<tok ID="anotherBar" fooID="shovel"/>
<tok ID="noFoo"/>

说明

  1. 匹配任何token元素的模板会创建一个tok元素,该元素具有匹配的token的所有现有属性(如果有)元素。它还将模板应用于任何fooID属性,其值与当前(匹配)节点的ID属性值相同。如果没有任何此类fooID` 属性,则不会进行进一步处理,也不会创建其他属性。

  2. fooID 属性匹配的模板必须生成 "fooID_{N}" 形式的新属性,其中 N 是当前节点(匹配的 fooID 属性)在节点列表(由 指令创建)中的位置,选择了当前模板以应用于此 fooID 属性)。如果 N 为 1,我们不会在名称 ("fooID") 的开头附加字符串 "_"{N}

  3. 为了避免默认 XSLT 处理的副作用,我们添加了与任何 fooSources 元素匹配的第三个模板,并且(该模板)具有空正文。

PS: I'd like to do this in xpath 1.0

XPath is a query language for XML documents and as such it cannot modify any nodes of the document.

To produce the wanted result (changing element names and adding new attributes to elements) you have to use another language that is hosting XPath. The most appropriate such language, created especially with the goal to be used for XML transformations is XSLT.

This XSLT 1.0 transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kFooIdByVal" match="fooSource/@fooID"
  use="."/>

 <xsl:template match="token">
  <tok>
   <xsl:copy-of select="@*"/>
   <xsl:apply-templates
        select="key('kFooIdByVal',@ID)"/>
  </tok>
 </xsl:template>

 <xsl:template match="@fooID">
  <xsl:variable name="vattrName"
   select="concat('fooID',
                  substring(concat('_',position()),
                            1 div (position() >1)
                           )
                  )
   "/>

  <xsl:attribute name="{$vattrName}">
   <xsl:value-of select="normalize-space(..)"/>
  </xsl:attribute>
 </xsl:template>
 <xsl:template match="fooSources"/>
</xsl:stylesheet>

when applied on the provided XML document:

<root>
    <myStuff>
        <tokens>
            <token ID="bar"/>
            <token ID="anotherBar"/>
            <token ID="noFoo"/>
        </tokens>
        <fooSources>
            <fooSource fooID="bar"> kitten </fooSource>
            <fooSource fooID="anotherBar"> shovel </fooSource>
        </fooSources>
        <fooSources>
            <fooSource fooID="bar"> kitty </fooSource>
            <fooSource fooID="notAnotherBar"> fridge </fooSource>
        </fooSources>
    </myStuff>
</root>

produces the wanted, correct result:

<tok ID="bar" fooID="kitten" fooID_2="kitty"/>
<tok ID="anotherBar" fooID="shovel"/>
<tok ID="noFoo"/>

Explanation:

  1. A template matching any token element creates a tok element that has all the existing attributes (if any) of the matchedtokenelement. It also applies templates on anyfooIDattribute, whose value is the same as the value of theIDattribute of the current (matched) node. If there isn't any suchfooID` attribute, no futher processing is done and no additional attributes are created.

  2. The template that matches a fooID attribute must generate a new attribute of the form "fooID_{N}" where N is the position of the current node (the matched fooID attribute) in the node-list (created by the <xsl:apply-templates> instruction that selected this current template for applying on this fooID attribute). If N is 1, we do not append to the start of the name ("fooID") the string "_"{N}.

  3. To avoid the side-effects of default XSLT processing we add a third template that matches any fooSources element and, (the template) has an empty body.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文