编辑 - 我找到了问题的解决方案并发布了问答here。
我希望处理符合美国国会图书馆EAD标准的XML(找到here)。不幸的是,关于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>
第二个例子
<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>
第三个例子
<ead>
<eadheader>
<archdesc>
<descgrp>
<bioghist>one</bioghist>
</descgrp>
<dsc>
<c01>
<c02>
<bioghist>three</bioghist>
</c02>
</c01>
</dsc>
</archdesc>
</eadheader>
</ead>
如您所见,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>
第二个例子的输出
<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>
第三个例子的输出
<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>
如果我想提取“第一个”bioghist值并将其放在<primary_record>
中,我不能简单地<xsl:apply-templates select="/ead/eadheader/archdesc/bioghist"
,因为该标记可能不是{{1}的直接后代}} 标签。它可能被<archdesc>
或<descgrp>
或其组合包裹。我不能<bioghist>
,因为这会将所有 select="//bioghist"
标记拉出来。我甚至不能<bioghist>
,因为那里可能没有select="//bioghist[1]"
标记,然后我会将值拉到<bioghist>
以下,这是“第二”,应该处理后面。
这已经很长了,但另一个问题是,可以有无限数量的<c01>
个节点,最多嵌套12个级别。我正在递归处理它们。我已经尝试将我正在处理的节点(例如<cxx>
)保存为名为“RN”的变量,然后运行<c01>
。这适用于某些形式的EAD,其中<xsl:apply-templates select=".//bioghist [name(..)=name($RN) or name(../..)=name($RN)]">
标签没有嵌套得太深,但如果它必须处理由喜欢在其他标签中包装标签的人创建的EAD文件,它将会失败(这完全是根据EAD标准很好。
我喜欢的是某种说法
<bioghist>
标记,但<bioghist>
代码我希望我的情况清楚。如果我留下任何含糊不清的地方,请告诉我。您将提供的任何帮助将不胜感激。感谢。
答案 0 :(得分:2)
由于要求相当模糊,任何答案都只反映了作者的猜测。
这是我的:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:names>
<n>primary_record</n>
<n>child_record</n>
<n>grandchild_record</n>
</my:names>
<xsl:variable name="vNames" select="document('')/*/my:names/*"/>
<xsl:template match="/">
<xsl:apply-templates select=
"//bioghist[following-sibling::node()[1]
[self::descgrp]
]"/>
</xsl:template>
<xsl:template match="bioghist">
<xsl:variable name="vPos" select="position()"/>
<xsl:element name="{$vNames[position() = $vPos]}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<ead>
<eadheader>
<archdesc>
<bioghist>first</bioghist>
<descgrp>
<bioghist>first</bioghist>
<bioghist>
<bioghist>first</bioghist></bioghist>
</descgrp>
<dsc>
<c01>
<bioghist>second</bioghist>
<descgrp>
<bioghist>second</bioghist>
<bioghist>
<bioghist>second</bioghist></bioghist>
</descgrp>
<c02>
<bioghist>third</bioghist>
<descgrp>
<bioghist>third</bioghist>
<bioghist>
<bioghist>third</bioghist></bioghist>
</descgrp>
</c02>
</c01>
</dsc>
</archdesc>
</eadheader>
</ead>
生成了想要的结果:
<primary_record>first</primary_record>
<child_record>second</child_record>
<grandchild_record>third</grandchild_record>
答案 1 :(得分:0)
我自己制定了一个解决方案并将其发布在Q&A,因为该解决方案非常特定于某个XML标准,并且似乎超出了此问题的范围。如果人们觉得最好也在这里发布,我可以用副本更新这个答案。