XPATH / XSLT:选择父节点属性与另一个节点属性匹配的节点

6
我正在尝试使用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>

我该如何选择正确的组织名称来关联作者?

非常感谢。

Jim


1
使用特定的XSLT功能进行交叉引用检查我的答案。 - user357812
4个回答

8
作为使用变量的替代方案,您可以利用“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>

4

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

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

1
我的直觉会选择@Tim C的解决方案,但这个更好。 - Wayne
谢谢Alejandro。我之前没有使用过XSLT键,所以会开始学习它们。 - JimS
@lwburk 为什么你认为这个解决方案更好?我对细节很感兴趣。谢谢。 - JimS
2
@JimS - 在@Tim的解决方案中,对于每个AuthorGroup/Author,我们都会跳回到父级以遍历Affiliation兄弟节点,直到找到具有正确OrgName的节点。这种方法可以实现目标,但是比较绕路,而且代价很高。在@Alejandro的解决方案中,我们采用了更自然的方式,即构建从机构ID到机构的映射。当你想在一本书中查找一个单词时,你不会从开头扫描每一页直到找到你要找的单词;你会在索引中查找。 - Wayne

2

快速回答一下……希望能帮到您,目前我不能运行它 :-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>

1
<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>



嗨,Naraen。谢谢你的回答。我无法使其工作,所以按照Tim的建议,用current()运算符替换了XPath表达式中的“.”。 - JimS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接