Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
XSLT仅当源属性存在时才向节点添加属性_Xslt_Xpath_Attributes - Fatal编程技术网

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

XSLT仅当源属性存在时才向节点添加属性,xslt,xpath,attributes,Xslt,Xpath,Attributes,我的意思是,当且仅当属性数据的源存在时,才向节点添加属性元素 换句话说,我不想以空属性结束,以防源与我的规则不匹配 <tok id="t1" fooID=""/> //not accepted <tok id="t1" /> //instead of ^ <tok id="t1" fooID="bar"/> //accepted 源XML如下所示: <root> <myStuff> <tokens>

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

换句话说,我不想以空属性结束,以防源与我的规则不匹配

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

源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:我想在XPath1.0中实现这一点

PS:我想在XPath1.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>
<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"/>

应用于提供的XML文档时

<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>
<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"/>

小猫
铲子
基蒂
冰箱
生成所需的正确结果

<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>
<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"/>

说明

<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>
<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"/>
  • 匹配任何
    标记
    元素的模板将创建一个
    tok元素,该元素具有匹配的
    标记
    元素的所有现有属性(如果有)。它还将模板应用于任何
    fooID
    属性,其值与当前(匹配)节点的
    ID
    属性的值相同。如果没有任何此类
    fooID`属性,则不会进行进一步的处理,也不会创建其他属性

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

  • 为了避免默认XSLT处理的副作用我们添加了第三个模板,该模板匹配任何
    fooSources
    元素,并且(模板)有一个空的主体

  • 
    
    好问题,+1。完整、简短、简单的XSLT 1.0解决方案见我的答案:)很漂亮。谢谢我实际上是想说XSLT而不是xpath,把它们搞混了……嗯,尽管在firefox中测试时一切都正常,但从使用Saxon 9.2的java程序调用时,`don show/work'返回的值似乎根本不起作用。。。知道为什么会这样吗?(没有错误,就好像没有匹配的值)@Twodordan:Java程序中的某个东西。。。此转换首先在Saxon上运行,然后在其他XSLT处理器上运行。。。所有这些都会产生相同的正确结果。@Dimitre你是对的。问题是(现在仍然是)我正在以web服务的形式运行我的程序。ApacheTomcat服务器(localhost)根本没有使用Saxon。必须弄清楚如何让它使用saxon9.jar。。。一直以来,我都以为我在使用saxon,但我不是Twodordan:转换是标准的XSLT1.0,任何兼容的XSLT1.0处理器(不仅仅是saxon)都会毫无问题地执行它。