数据结构未知时排除某些子节点

aar*_*dev 5 xslt xpath xml-parsing

编辑 - 我已经找到解决问题的方法,并在此处发布了问答.

我正在寻找符合美国国会图书馆EAD标准的XML(在此处找到).不幸的是,关于XML的结构,标准非常宽松.

例如,<bioghist>标签可以存在于<archdesc>标签内,或<descgrp>标签内,或嵌套在另一个<bioghist>标签内,或上述的组合中,或者可以完全省略.我发现很难选择我正在寻找的bioghist标签而不选择其他标签.

以下是我的XSLT可能必须处理的一些不同的可能的EAD XML文档:

第一个例子

<ead>
<eadheader>
    <archdesc>
        <bioghist>one</bioghist>
        <dsc>
            <c01>
                <descgrp>
                    <bioghist>two</bioghist>
                </descgrp>
                <c02>
                    <descgrp>
                        <bioghist>
                            <bioghist>three</bioghist>
                        </bioghist>
                    </descgrp>
                </c02>
            </c01>
        </dsc>
    </archdesc>
</eadheader>
</ead>
Run Code Online (Sandbox Code Playgroud)

第二个例子

<ead>
<eadheader>
    <archdesc>
        <descgrp>
            <bioghist>
                <bioghist>one</bioghist>
            </bioghist>
        </descgrp>
        <dsc>
            <c01>
                <c02>
                    <descgrp>
                        <bioghist>three</bioghist>
                    </descgrp>
                </c02>
                <bioghist>two</bioghist>
            </c01>
        </dsc>
    </archdesc>
</eadheader>
</ead>
Run Code Online (Sandbox Code Playgroud)

第三个例子

<ead>
<eadheader>
    <archdesc>
        <descgrp>
            <bioghist>one</bioghist>
        </descgrp>
        <dsc>
            <c01>
                <c02>
                    <bioghist>three</bioghist>
                </c02>
            </c01>
        </dsc>
    </archdesc>
</eadheader>
</ead>
Run Code Online (Sandbox Code Playgroud)

如您所见,EAD XML文件<bioghist>几乎可以在任何地方使用标记.我想要产生的实际输出太复杂了,不能在这里发布.以上三个EAD示例的输出的简化示例可能如下:

第一个例子的输出

<records>
<primary_record>
    <biography_history>first</biography_history>
</primary_record>
<child_record>
    <biography_history>second</biography_history>
</child_record>
<granchild_record>
    <biography_history>third</biography_history>
</granchild_record>
</records>
Run Code Online (Sandbox Code Playgroud)

输出第二个例子

<records>
<primary_record>
    <biography_history>first</biography_history>
</primary_record>
<child_record>
    <biography_history>second</biography_history>
</child_record>
<granchild_record>
    <biography_history>third</biography_history>
</granchild_record>
</records>
Run Code Online (Sandbox Code Playgroud)

输出第三个例子

<records>
<primary_record>
    <biography_history>first</biography_history>
</primary_record>
<child_record>
    <biography_history></biography_history>
</child_record>
<granchild_record>
    <biography_history>third</biography_history>
</granchild_record>
</records>
Run Code Online (Sandbox Code Playgroud)

如果我想拉出"第一个"bioghist值并将其放入<primary_record>,我不能简单地说<xsl:apply-templates select="/ead/eadheader/archdesc/bioghist",因为该标签可能不是标签的直接后代<archdesc>.它可以由一个<descgrp>或多个<bioghist>或它们的组合包裹.我不能select="//bioghist",因为这将拉动所有<bioghist>标签.我甚至不能select="//bioghist[1]"因为那里可能没有<bioghist>标签,然后我会将值拉到下面<c01>,这是"秒",应该稍后处理.

这已经是一个很长的帖子,但另一个问题是可以有无限数量的<cxx>节点,最多嵌套12个级别.我正在递归处理它们.我已经尝试将我正在处理的节点(<c01>例如)保存为名为"RN"的变量,然后运行<xsl:apply-templates select=".//bioghist [name(..)=name($RN) or name(../..)=name($RN)]">.这适用于某些形式的EAD,其中<bioghist>标签没有嵌套太深,但如果它必须处理由喜欢在其他标签中包装标签的人创建的EAD文件,它将失败(根据EAD,这完全没问题)标准).

我所喜欢的就是说

  • <bioghist>在当前节点下面的任何位置获取任何标记
  • 如果你碰到一个<c??>标签,不要深入挖掘

我希望我的情况清楚.如果我留下任何含糊不清的地方,请告诉我.您将提供的任何帮助将不胜感激.谢谢.

aar*_*dev 0

我自己制定了一个解决方案并将其发布在这个问答中,因为该解决方案非常特定于某个 XML 标准,并且似乎超出了这个问题的范围。如果人们觉得最好也将其发布在这里,我可以用副本更新此答案。