0

所以我有一个从 php curl 响应生成的 XML 文件,然后将其转换为 CSV,这样下面的每个 mods 元素都是一行。我在此处检查的答案中使用样式表得到了一些 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: &apos;War Views. No.179.  Ruins of the Northeastern Railway Depot, Charleston.&apos;  This is a stereograph image which measures 3 1/2&quot; X 7&quot;.  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>&#xD;</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

.......等等。

因此,当节点(例如多个主题 -> 地理条目)匹配时,它们会被分组并用分号分隔,而不是占用多个逗号分隔的值?希望我有点道理。谢谢!

4

1 回答 1

2

一种方法是首先将您的 XSLT 更改为仅选择没有具有相同子名称的前置兄弟的元素(即选择每个组中的“第一个”元素)

<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() &gt; 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>&#xD;</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构造,其中包括对“group-adjacent”的操作。而且,您还可以使用改进的XSL:值将在选择多个元素时使用“分离器”属性,从而消除递归模板。

对于 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() &gt; 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>&#xD;</xsl:text>
    </xsl:template>
</xsl:stylesheet>
于 2013-10-12T08:26:54.097 回答