合并 xml - 将元素名称从文档 b 引入文档 a 作为属性值,匹配子文本(或位置?)

问题描述 投票:0回答:1

👋您好,提前感谢您的任何建议!

XML A
元数据导出a
元素名称是自定义的,反映本地字段名称
元素子文本在内容、文档顺序上与 B 相同

<metadata>
   <record>
      <Title>Untitled</Title>
      <Photographer>Gordon Parks</Photographer>
      <Notes>An important photograph because (...)</Notes>
   </record>
   ...
</metadata>

XML B
元数据导出b
元素名称反映了到都柏林核心元素/术语的配置映射
元素子文本在内容、文档顺序上与 A 相同

<metadata>
   <record>
      <title>Untitled</title>
      <creator>Gordon Parks</creator>
      <description>An important photograph because (...)</description>
   </record>
   ...
</metadata>

所需输出
使用本地字段名称作为元素名称
将 DC 元素/项捕获为 @dc 值

<metadata>
   <record>
      <Title dc="title">Untitled</Title>
      <Photographer dc="creator">Gordon Parks</Photographer>
      <Notes dc="description">An important photograph because (...)</Notes>
   </record>
   ...
</metadata>

目前的样式表

    <xsl:template match="/">
        <metadata>
            <xsl:for-each select="XML_A/metadata/record">
                <record>
                    <xsl:for-each select="node()">
                        <xsl:choose>
                            <xsl:when test="name() != ''">
                            <!-- minor issue above: without this I believe I was selecting whitespace and/or other nodes...
                            ...ERROR description: "Supplied element name is a zero-length string" -->
                                <xsl:element name="{name()}">
                                    <!-- ACK -->
                                    <xsl:value-of select="."/>
                                </xsl:element>
                            </xsl:when>
                            <xsl:otherwise/>
                        </xsl:choose>
                    </xsl:for-each>
                </record>
            </xsl:for-each>
        </metadata>
    </xsl:template>

关于

<!-- ACK -->

正如我上面所说,我相信 A 和 B 中具有相同子文本的序列节点是相同的。因此,对于 A 中每条记录的每个子节点,我认为我可以使用 either

position()
 text()
匹配B中对应的节点。但是...

我尝试实现一个键来匹配 A 和 B 之间所需的元数据/记录(给定的 ID 元素值,未在 XML A 和 B 的示例中显示,可用于匹配记录)。

<xsl:key name="match_xml_b" match="record" use="b_id">
...

<xsl:attribute name="dc"
   select="key('match_xml_b', a_id, document('XMLB.xml')/[text() = $a_text]/name()/>

...or...

<xsl:attribute name="dc"
   select="key('match_xml_b', a_id, document('XMLB.xml')/[position() = $a_position]/name()/>

我认为我的语法对于选择

record
的子节点不正确,其中文本内容与 A 中当前节点的文本内容匹配(或者位置与 A 中当前节点的位置匹配)。此外,我不确定使用什么 XPath 语法来选择 B 中的元素名称,这正是我的所需输出中需要的。

我也尝试过一些没有钥匙的笨拙匹配,类似于......

<xsl:attribute name="dc" 
   select="document('XMLB.xml')/metadata/record[b_id = a_id]/[position() = $a_position]
   (: how to use name() here? :)"/>

or...

<xsl:attribute name="dc" 
   select="document('XMLB.xml')/metadata/record[b_id = a_id]/[text() = $a_text]
   (: how to use name() here? :)"/>

...不成功。

我这里的困难包括使用

record
position()
匹配
text()
的子元素的语法,以及检索匹配后的元素的 name

xml xpath xslt xslkey
1个回答
0
投票

如果允许通过匹配文本来链接元素,您可以执行类似以下操作:

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

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

<xsl:key name="keyB" match="*" use="text()" />

<xsl:template match="/metadata">
    <metadata>
        <xsl:for-each select="record">
            <record>
                <xsl:for-each select="*">
                    <xsl:copy>
                        <xsl:attribute name="dc" select="key('keyB', text(), $xmlB)/name()"/>
                        <xsl:apply-templates/>
                    </xsl:copy>
                </xsl:for-each>
            </record>
        </xsl:for-each>
    </metadata>
</xsl:template>

</xsl:stylesheet> 

这需要 XSLT 2.0 或更高版本。

© www.soinside.com 2019 - 2024. All rights reserved.