匹配来自两个 XML 文件的 ID,并从具有相同 ID 的元素中获取字符串

Match IDs from two XML files and get strings from element with same ID

如何确保只有第二个文件中匹配的人物元素的persName成为第一个文件中人物元素的persName?

所以我有两个 XML 个文件。

第一个看起来像这样:

...
<teiHeader>
 ...
 <profileDesc>
 ...
  <particDesc>
   <listPerson>
    <person role="" ref="#11988">
     <persName/>
    </person>
    <person role="" ref="#13163">
     <persName/>
    </person>
    <person role="" ref="#38909">
     <persName/>
    </person>
    <person role="" ref="#38969">
     <persName/>
    </person>
    <person role="" ref="#11910">
     <persName/>
    </person>
   </listPerson>
  </particDesc>
 </profileDesc>
 ...
</teiHeader>
...

它包含 @ref 属性中人员的 ID。

第二个 (= listPerson.xml) 看起来像这样:

...
</teiHeader>
<text>
 <body>
  <div type="persons">
   <person xml:id="#11988">
    <persName>
     <forename>Forename1</forename>
     <surname>Surname1</surname>
    <persName>
   </person>
   <person xml:id="#13163">
    <persName>
     <forename>Forename2</forename>
     <surname>Surname2</surname>
    <persName>
   </person>
   <person xml:id="#38909">
    <persName>
     <forename>Forename3</forename>
     <surname>Surname3</surname>
    <persName>
   </person>
   <person xml:id="#38969">
    <persName>
     <forename>Forename4</forename>
     <surname>Surname4</surname>
    <persName>
   </person>
  <person xml:id="#11910">
    <persName>
     <forename>Forename5</forename>
     <surname>Surname5</surname>
    <persName>
   </person>
  </div>
 </body>
</text>

因此此文件包含与第一个文件相同的 ID,但在 @xml:id 属性中。此外,它还包含 <persName>.

中的人员姓名

我要做的是匹配ID(@ref@xml:id的属性值)然后复制<forename><surname>到使用 XSLT 在第一个文件中的正确位置。

我当前的样式表如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:tei="http://www.tei-c.org/ns/1.0"
    exclude-result-prefixes="xs"
    version="2.0">
    
    <xsl:output method="xml" version="1.0" indent="yes"/>
    
    <!-- copy all -->
    <xsl:template match="@* | node()" name="identity-copy">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy> 
    </xsl:template>
    
    <!-- match ids, get persName -->
    <xsl:variable name="listPers" select="document('listPerson.xml')"/>
    
    <xsl:template match="//tei:persName"> 
        
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        
            <xsl:variable name="pers-ref" select="//tei:person/@ref"/>
        
            <xsl:variable name="pers-info" select="$listPers//tei:person[@xml:id=$pers-ref]/." />
            
            <xsl:for-each select="$pers-info">
                <xsl:value-of select="tei:persName/tei:forename,tei:persName/tei:surname"/>
            </xsl:for-each>
                        
        </xsl:copy> 
    </xsl:template>
</xsl:stylesheet>

目前,这不起作用。我得到的是这个(如文件 1 中所希望的那样):

<person role="" ref="#11988">
 <persName>Forename5 Surname5Forename4 Surname4Forename3 Surname3Forename2 Surname2Forename1 Surname1</persName>
</person>
<person role="" ref="#13163">
 <persName>Forename5 Surname5Forename4 Surname4Forename3 Surname3Forename2 Surname2Forename1 Surname1</persName>
</person>

等等...

我想得到的是:

<person role="" ref="#11988">
 <persName>Forename1 Surname1</persName>
</person>
<person role="" ref="#13163">
 <persName>Forename2 Surname2</persName>
</person>

等 (但是不要假设persNames是有序的,这都是关于属性匹配的。)

提前致谢!

<xsl:variable name="pers-ref" select="//tei:person/@ref"/>

将 select 所有 @ref tei:persons - 这就是使用以 // 开头的绝对路径的原因做。你只想要当前的人。

要么使用相对路径 - 在 <xsl:template> 中,您位于 persName 元素中,您感兴趣的 @ref 属性在父元素中:

<xsl:variable name="pers-ref" select="../@ref"/>

或者您完全跳过额外变量并使用 current() XSLT 函数:

<xsl:template match="tei:persName"> 
    <xsl:variable name="pers-info" select="$listPers//tei:person[@xml:id=current()/../@ref]/tei:persName" />
    <xsl:copy>
        <xsl:apply-templates select="@*" />
        <xsl:value-of select="$pers-info/tei:forename, $pers-info/tei:surname" />
    </xsl:copy> 
</xsl:template>

另请注意,match 表达式不需要锚定。 match="//tei:persName" 没用。 match="tei:persName"更好。

我建议使用 key 来解析交叉引用。这是一个 简化的 示例:

XML

<teiHeader>
 <profileDesc>
  <particDesc>
   <listPerson>
    <person role="" ref="#11988">
     <persName/>
    </person>
    <person role="" ref="#13163">
     <persName/>
    </person>
    <person role="" ref="#38909">
     <persName/>
    </person>
    <person role="" ref="#38969">
     <persName/>
    </person>
    <person role="" ref="#11910">
     <persName/>
    </person>
   </listPerson>
  </particDesc>
 </profileDesc>
</teiHeader>

listPerson.xml(固定为合式!!)

<text>
 <body>
  <div type="persons">
   <person xml:id="#11988">
    <persName>
     <forename>Forename1</forename>
     <surname>Surname1</surname>
    </persName>
   </person>
   <person xml:id="#13163">
    <persName>
     <forename>Forename2</forename>
     <surname>Surname2</surname>
    </persName>
   </person>
   <person xml:id="#38909">
    <persName>
     <forename>Forename3</forename>
     <surname>Surname3</surname>
    </persName>
   </person>
   <person xml:id="#38969">
    <persName>
     <forename>Forename4</forename>
     <surname>Surname4</surname>
    </persName>
   </person>
  <person xml:id="#11910">
    <persName>
     <forename>Forename5</forename>
     <surname>Surname5</surname>
    </persName>
   </person>
  </div>
 </body>
</text>

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:param name="listPers" select="document('listPerson.xml')"/>

<xsl:key name="pers" match="person" use="@xml:id" />

<xsl:template match="teiHeader">
    <output>
        <xsl:for-each select="//person">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                 <persName>
                    <xsl:value-of select="key('pers', @ref, $listPers)/persName/(forename, surname)" />
                 </persName>
            </xsl:copy>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

结果

<?xml version="1.0" encoding="utf-8"?>
<output>
   <person role="" ref="#11988">
      <persName>Forename1 Surname1</persName>
   </person>
   <person role="" ref="#13163">
      <persName>Forename2 Surname2</persName>
   </person>
   <person role="" ref="#38909">
      <persName>Forename3 Surname3</persName>
   </person>
   <person role="" ref="#38969">
      <persName>Forename4 Surname4</persName>
   </person>
   <person role="" ref="#11910">
      <persName>Forename5 Surname5</persName>
   </person>
</output>