所以我有一个XML文件,我是从php curl响应生成的,然后转换为CSV,这样下面的每个mods元素都是一行。我在检查的答案here中使用样式表获得了一些CSV,但这并不是我想要做的。
我的XML(简化):
<xml>
<mods xmlns="http://www.loc.gov/mods/">
<typeOfResource>StillImage</typeOfResource>
<titleInfo ID="T-1">
<title>East Bay Street</title>
</titleInfo>
<subject ID="SBJ-2">
<topic>Railroads</topic>
</subject>
<subject ID="SBJ-3">
<geographic>Low Country</geographic>
</subject>
<subject ID="SBJ-4">
<geographic>Charleston (S.C.)</geographic>
</subject>
<subject ID="SBJ-7">
<hierarchicalGeographic>
<county>Charleston County (S.C.)</county>
</hierarchicalGeographic>
</subject>
<physicalDescription>
<form>Images</form>
</physicalDescription>
<note>Caption: 'War Views. No.179. Ruins of the Northeastern Railway Depot, Charleston.' This is a stereograph image which measures 3 1/2" X 7". Date assumed to be 1865.</note>
<originInfo>
<dateCreated>1865</dateCreated>
</originInfo>
<location>
<physicalLocation>The Charleston Museum Archives</physicalLocation>
</location>
<relatedItem type="host">
<titleInfo>
<title>Charleston Museum Civil War Photographs</title>
</titleInfo>
</relatedItem>
</mods>
<mods>
more nodes...
</mods>
</xml>
我上面的堆栈帖子中的当前XSL:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:strip-space elements="*" />
<xsl:template match="/*/child::*">
<xsl:for-each select="child::*">
<xsl:if test="position() != last()"><xsl:value-of select="normalize-space(.)"/>, </xsl:if>
<xsl:if test="position() = last()"><xsl:value-of select="normalize-space(.)"/> <xsl:text>
</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
这输出CSV,其中每个MODS元素是一行,并且每个子节点在该行上是逗号分隔值。是否可以修改XSL,使每个MODS元素是一行,但匹配的子元素的值是否分组?类似的东西:
StillImage,East Bay Street,Railroads,**Low County;Charleston (S.C.)**,Charleston County (S.C.), Images
.......等等。
因此,当节点(如多个主题 - >地理条目)匹配时,它们被分组并以分号分隔,而不是占用多个逗号分隔值?希望我有道理。谢谢!
答案 0 :(得分:2)
执行此操作的一种方法是首先将XSLT更改为仅选择没有具有相同子名称的previous-sibling的元素(即选择每个组中“first”的元素)
<xsl:for-each select="*[name(*) != name(preceding-sibling::*[1]/*)]">
然后,您可以定义一个变量来获取以下兄弟,如果(并且仅当)它具有相同的名称,那么您可以检查当前元素是否确实在一个大于1的组中。
<xsl:variable name="nextWithSameName"
select="following-sibling::*[1][name(*)=name(current()/*)]"/>
<xsl:if test="$nextWithSameName">**</xsl:if>
(我不确定你是否真的想要在最终结果中使用**,或者他们是否只是为了突出显示该组!我将它们保留在我的示例中,但显然很容易删除相关内容代码行。)
要将具有相同名称的兄弟姐妹组合在一起,您可以为第一个兄弟姐妹调用递归模板
<xsl:apply-templates select="$nextWithSameName" mode="group"/>
然后,在这个模板中,你会递归地调用它,紧接着的兄弟会有同样的名字
<xsl:template match="*" mode="group">
<xsl:text>;</xsl:text>
<xsl:value-of select="normalize-space(.)"/>
<xsl:apply-templates select="following-sibling::*[1][name(*)=name(current()/*)]" />
</xsl:template>
尝试以下XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*/*">
<xsl:for-each select="*[name(*) != name(preceding-sibling::*[1]/*)]">
<xsl:variable name="nextWithSameName" select="following-sibling::*[1][name(*)=name(current()/*)]"/>
<xsl:if test="position() > 1">, </xsl:if>
<xsl:if test="$nextWithSameName">**</xsl:if>
<xsl:value-of select="normalize-space(.)"/>
<xsl:apply-templates select="$nextWithSameName" mode="group"/>
<xsl:if test="$nextWithSameName">**</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="*" mode="group">
<xsl:text>;</xsl:text>
<xsl:value-of select="normalize-space(.)"/>
<xsl:apply-templates select="following-sibling::*[1][name(*)=name(current()/*)]" />
</xsl:template>
</xsl:stylesheet>
现在,如果你可以使用XSLT 2.0,事情会变得更加容易,因为你可以使用 xsl:for-each-group 构造,其中包括一个操作, “组相邻”。您还可以使用改进的 xsl:value-of 来取消递归模板,当选择多个元素时,该属性将具有“separator”属性。
对于XSLT 2.0,以下内容也应该起作用
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*/*">
<xsl:for-each-group select="*" group-adjacent="name(*)">
<xsl:if test="position() > 1">, </xsl:if>
<xsl:if test="current-group()[2]">**</xsl:if>
<xsl:value-of select="current-group()" separator=";" />
<xsl:if test="current-group()[2]">**</xsl:if>
</xsl:for-each-group >
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>