你好Stackoverflowers-
这是我第一次发帖。我遇到了一个令人沮丧的XSLT问题,尽管提出了各种设想的解决方案,但仍未能解决。该方案是将一个XML文档(#1)基本转换为另一个(#2)格式,以实现两个系统之间的互操作性。
XML文档#1包含许多重复的元素,每个元素包含一个单独的值。这些重复的元素需要转换为doc#2的替代元素,并包含来自doc#1的相应值。
尽管进行了大量实验,但我似乎无法使它正常工作。 doc#1中的相关元素如下:
<mods:extension>
<rx:funder>Funder A</rx:funder>
<rx:projectid>Funder A code number</rx:projectid>
<rx:funder>Funder B</rx:funder>
<rx:projectid>Funder B code number</rx:projectid>
</mods:extension>
我需要到XML中以在文档#2中进行转换,如下所示:
<project_input>
<item>
<project>Funder A code number</project>
<funder_name>Funder A</funder_name>
</item>
<item>
<project>Funder B code number</project>
<funder_name>Funder B</funder_name>
</item>
</project_input>
但不幸的是,我的转换输出始终是以下内容的变体:
<project_input>
<item>
<project>Funder A code numberFunder B code number</project>
<funder_name>Funder AFunder B</funder_name>
</item>
</project_input>
...将值填充到单个元素中。
目前的转换是这样的:
<xsl:if test="v3:extension">
<project_input>
<item>
<xsl:for-each select="v3:extension/rx:projectid">
<project>
<xsl:value-of select="."/>
</project>
</xsl:for-each>
<xsl:for-each select="v3:extension/rx:funder">
<funder_name>
<xsl:value-of select="."/>
</funder_name>
</xsl:for-each>
</item>
</project_input>
</xsl:if>
因此,问题在于,尽管正确的值在doc#1中成功循环,但在doc#2中没有正确输出。
我尝试使用合并了不同值的变体,但这也不成功。令人沮丧的是,我以前做过这样的事情,但我一辈子都记不起来了!堆栈上也已经描述了类似的场景,但是在那里提出的解决方案似乎在这种用例中不起作用。
有人可以指出我所缺少的明显东西吗?谢谢
已更新问题-请参阅下面的评论。这需要在XSLT 1.0中工作。我设法把一些东西凑齐了。只要提取,排序和分组了正确的数据,它就可以正常工作,但是缺少指定的XML元素。我可能已经忽略了一些很明显的东西。
有人可以帮助我吗?这是XSLT 1.0:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mods="http://www.loc.gov/mods/v3" xmlns:rx="http://example.com/rx"
version="1.0">
<xsl:output indent="yes"/>
<xsl:key use="rx:funder" match="mods:mods/mods:extension" name="groups" />
<xsl:template match="/">
<xsl:apply-templates select="mods:mods/mods:extension" />
</xsl:template>
<xsl:template match="mods:mods">
<rioxx2_project_output>
<xsl:for-each select="/mods:extension[generate-id(.)=generate-
id(key('groups', rx:funder))]">
<item>
<funder_name>
<xsl:value-of select="mods:extension/rx:funder/text()" />
</funder_name>
<project>
<xsl:value-of select="mods:extension/rx:projectid/text()" />
</project>
</item>
</xsl:for-each>
</project_input>
</xsl:template>
</xsl:stylesheet>
这里在XSLT小提琴中:https://xsltfiddle.liberty-development.net/bFN1y8S/1
答案 0 :(得分:1)
这似乎是使用for-each-group group-starting-with
或group-ending-with
的经典示例,因此在您的情况下,例如使用
<xsl:template match="mods:extension">
<project_input>
<xsl:for-each-group select="*" group-starting-with="rx:funder">
<item>
<project>
<xsl:value-of select="current-group()[2]"/>
</project>
<funder_name>
<xsl:value-of select="."/>
</funder_name>
</item>
</xsl:for-each-group>
</project_input>
</xsl:template>
假设mods:extension的子元素的序列具有一定规律性,rx:funder
可以识别组。
使用XSLT 3的完整示例https://xsltfiddle.liberty-development.net/bFN1y8S(对于XSLT 2处理器,您需要拼写身份转换模板而不是使用xsl:mode
)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mods="http://example.com/mods"
xmlns:rx="http://example.com/rx"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="mods:extension">
<project_input>
<xsl:for-each-group select="*" group-starting-with="rx:funder">
<item>
<project>
<xsl:value-of select="current-group()[2]"/>
</project>
<funder_name>
<xsl:value-of select="."/>
</funder_name>
</item>
</xsl:for-each-group>
</project_input>
</xsl:template>
</xsl:stylesheet>
要在XSLT 1中实现类似的方法,一种方法是使用一个密钥,该密钥在前一个兄弟rx:funder
的id上键入任何非rx:funder
元素:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mods="http://example.com/mods"
xmlns:rx="http://example.com/rx"
exclude-result-prefixes="mods rx"
version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group" match="mods:extension/*[not(self::rx:funder)]"
use="generate-id(preceding-sibling::rx:funder[1])"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="mods:extension">
<project_input>
<xsl:for-each select="rx:funder">
<item>
<project>
<xsl:value-of select="key('group', generate-id())[self::rx:projectid]"/>
</project>
<funder_name>
<xsl:value-of select="."/>
</funder_name>
</item>
</xsl:for-each>
</project_input>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
<xsl:strip-space elements="*"/>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="mods:extension">
<xsl:element name="project_input">
<xsl:for-each-group select="node()" group-starting-with="rx:funder">
<item>
<project>
<xsl:value-of select="./following-sibling::*[1][self::rx:projectid]"/>
</project>
<funder_name>
<xsl:value-of select="."/>
</funder_name>
</item>
</xsl:for-each-group>
</xsl:element>
</xsl:template>
Kindly chek it.