【问题标题】:XPATH / XSLT: Selecting a node where the parent node's attribute matches the attribute of another nodeXPATH / XSLT:选择父节点的属性与另一个节点的属性匹配的节点
【发布时间】:2011-03-29 12:55:13
【问题描述】:

我正在尝试使用 XPath 和 XSLT 对以下 XML 应用转换。

<AuthorGroup>
  <Author AffiliationID="A1">
    <GivenName>John</GivenName>
    <Initials/>
    <FamilyName>Smith</FamilyName>
    <Degrees/>
    <Roles/>
  </Author>
    <Author AffiliationID="A2">
    <GivenName>Bill</GivenName>
    <Initials/>
    <FamilyName>Atkins</FamilyName>
    <Degrees/>
    <Roles/>
  </Author>
  <Affiliation AFFID="A1">
    <OrgDivision/>
    <OrgName>Some Org</OrgName>
    <OrgAddress/>
  </Affiliation>
  <Affiliation AFFID="A2">
    <OrgDivision/>
    <OrgName>Another Org</OrgName>
    <OrgAddress/>
  </Affiliation>
</AuthorGroup>

我正在尝试将作者和从属机构名称合并到一个节点下,所以我最终会得到如下结构:

<AUG>
  <AU><NAME>John Smith</NAME><AUINFO>Some Org</AUINFO></AU>
  <AU><NAME>Bill Atkins</NAME><AUINFO>Another Org</AUINFO></AU>
</AUG>

我正在努力寻找一种方法来选择一个节点的值,该节点的父节点的属性与另一个节点的属性值匹配。例如,对于作者 John Smith,我想选择与从属 ID 匹配的节点的值。

到目前为止,我的样式表中有一些代码,如下所示,但我知道节点内的选择不起作用。

<xsl:for-each select="AuthorGroup/Author">
  <AU>
  <NAME><xsl:value-of select="./FamilyName" /> <xsl:value-of select="./GivenName" /></NAME>
  <AUINFO><xsl:value-of select="../Affiliation[@AFFID='NEED TO MATCH AUTHOR AFFILIATIONID']/OrgName" /> </AUINFO>


  </AU>         
</xsl:for-each>

我应该如何为相关作者选择正确的组织名称的值?

非常感谢

吉姆

【问题讨论】:

  • 使用交叉引用的特定 XSLT 功能检查我的答案。

标签: xml xslt xpath


【解决方案1】:

作为使用变量的替代方法,您可以使用“current()”运算符来获取您所在的当前作者节点

<xsl:value-of select="../Affiliation[@AFFID=current()/@AffiliationID]/OrgName"/>

因此,如果您采用以下样式表

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:template match="/">
      <AUG>
         <xsl:for-each select="AuthorGroup/Author">
            <AU>
               <NAME>
                  <xsl:value-of select="./FamilyName"/>
                  <xsl:value-of select="./GivenName"/>
               </NAME>
               <AUINFO>
                  <xsl:value-of select="../Affiliation[@AFFID=current()/@AffiliationID]/OrgName"/>
               </AUINFO>
            </AU>
         </xsl:for-each>
      </AUG>
   </xsl:template>
</xsl:stylesheet>

然后应用你给定的 XML,结果应该是这样的

<AUG>
   <AU>
      <NAME>SmithJohn</NAME>
      <AUINFO>Some Org</AUINFO>
   </AU>
   <AU>
      <NAME>AtkinsBill</NAME>
      <AUINFO>Another Org</AUINFO>
   </AU>
</AUG>

【讨论】:

    【解决方案2】:

    键是交叉引用的正确工具。这个样式表:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:strip-space elements="*"/>
        <xsl:key name="kAffiliationByAFFID" match="Affiliation" use="@AFFID"/>
        <xsl:template match="AuthorGroup">
            <AUG>
                <xsl:apply-templates/>
            </AUG>
        </xsl:template>
        <xsl:template match="Author">
            <AU>
                <NAME>
                    <xsl:value-of select="concat(GivenName,' ',FamilyName)"/>
                </NAME>
                <xsl:apply-templates
                     select="key('kAffiliationByAFFID',@AffiliationID)"
                     mode="out"/>
            </AU>
        </xsl:template>
        <xsl:template match="Affiliation"/>
        <xsl:template match="Affiliation" mode="out">
            <AUINFO>
                <xsl:apply-templates/>
            </AUINFO>
        </xsl:template>
    </xsl:stylesheet>
    

    输出:

    <AUG>
        <AU>
            <NAME>John Smith</NAME>
            <AUINFO>Some Org</AUINFO>
        </AU>
        <AU>
            <NAME>Bill Atkins</NAME>
            <AUINFO>Another Org</AUINFO>
        </AU>
    </AUG>
    

    【讨论】:

    • 我的直觉是@Tim C 的解决方案,但这要好得多。
    • 谢谢亚历杭德罗。我以前没有使用过 xslt 键,所以将开始学习它们。
    • @lwburk 为什么你认为这个解决方案要好得多?我会对细节感兴趣。谢谢。
    • @JimS - 在@Tim 的解决方案中,对于每个AuthorGroup/Author,我们跳回到父级以遍历Affiliation 兄弟姐妹,直到找到具有正确OrgName 的兄弟姐妹。这行得通,但它是一种迂回的方式来询问我们想要什么。而且很贵。在@Alejandro 的解决方案中,我们做了一件更自然的事情,即构建从属 I​​D 到从属关系的映射。当您想在一本书中查找一个单词时,您不会从头开始扫描每一页,直到找到您要查找的单词。你在索引中查找它。
    【解决方案3】:

    只是一个快速的答案......希望这会有所帮助,暂时不能自己运行它:-S 您可以将 ID 放入变量中,例如:

    <xsl:for-each select="AuthorGroup/Author">
      <xsl:variable name="affID" select="@AFFID" />
      <AU>
        <NAME><xsl:value-of select="./FamilyName" /> <xsl:value-of select="./GivenName" /></NAME>
        <AUINFO><xsl:value-of select="../Affiliation[@AFFID=$affID]/OrgName" /> </AUINFO>
      </AU>         
    </xsl:for-each>
    

    【讨论】:

      【解决方案4】:
      <xsl:for-each select="AuthorGroup/Author">
          <AU>
          <NAME><xsl:value-of select="./FamilyName" /> <xsl:value-of select="./GivenName" />
          </NAME>
           <AUINFO><xsl:value-of select="../Affiliation[@AFFID=./@AffiliationID]/OrgName" /> 
           </AUINFO>
      


      【讨论】:

      • 嘿纳兰。感谢您的回答。我无法让它工作,所以更换了 .按照 Tim 的建议,在 XPath 表达式中使用 current() 运算符。
      猜你喜欢
      • 2015-07-09
      • 2013-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 1970-01-01
      • 2013-11-24
      • 1970-01-01
      相关资源
      最近更新 更多