使用 xstl 2.0 合并两个 xml 文件时如何保持第一个文件中元素的顺序
How to keep order of elements in first file when merging two xml files using xstl 2.0
我有两个 XML 文件,其中包含 header 部分和预告片。该部分本身有部分 header、部分详细信息和部分预告片。我需要在两个级别合并这两个文件 - 首先在部分级别,然后在部分详细信息级别。我希望我的结果基于第一个文件(Headers,预告片将来自第一个文件)。如果该部分匹配,我需要保留第一个文件中部分详细信息的顺序(没有用于排序的排序键,只有出现顺序)。如果第一个文件中没有节,我需要从第二个文件中添加整个节。
我有 xsl,它给出了结果,但顺序不正确。我需要有关如何订购它们的帮助。我没有尝试密钥查找,因为我不确定如何解释第一个文件中不存在的部分。
当 SectionDetails 匹配时,我需要第一个文件中的记录出现在第二个文件中的记录之前。
我的第一个文件 FileA 在这里
<FileRecord>
<HeaderRecord>
<A>FileA</A>
</HeaderRecord>
<SectionRecord Subject="Science">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Physics">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Biology">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="Math">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Algebra">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Calculus">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Geometry">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<TrailerRecord>
<A>FileA</A>
</TrailerRecord>
</FileRecord>
第二个文件FileB在这里
<FileRecord>
<HeaderRecord>
<A>FileB</A>
</HeaderRecord>
<SectionRecord Subject="Science">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Chemistry">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="Math">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Geometry">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="History">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Ancient">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Modern">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<TrailerRecord>
<A>FileB</A>
</TrailerRecord>
</FileRecord>
我正在使用的 xsl 在这里
<xsl:stylesheet version="2.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="xsd xsi xsl"
>
<xsl:param name="filebrecs" select="document('FileB.xml')"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="FileRecord"/>
</xsl:template>
<xsl:template match="FileRecord">
<FileRecord>
<xsl:apply-templates select="HeaderRecord"/>
<xsl:for-each-group select="SectionRecord, $filebrecs/FileRecord/SectionRecord" group-by="@Subject">
<SectionRecord>
<xsl:attribute name="Subject"><xsl:value-of select="current-grouping-key()"/> </xsl:attribute>
<xsl:apply-templates select="current-group()[1]/SectionHeader"/>
<xsl:for-each-group select="current-group()//SectionDetails" group-by="@Stream">
<xsl:for-each select="current-group()">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:for-each-group>
<xsl:apply-templates select="current-group()[1]/SectionTrailer"/>
</SectionRecord>
</xsl:for-each-group>
<xsl:apply-templates select="TrailerRecord"/>
</FileRecord>
</xsl:template>
</xsl:stylesheet>
我期待这样的结果
<FileRecord>
<HeaderRecord>
<A>FileA</A>
</HeaderRecord>
<SectionRecord Subject="Science">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Physics">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Biology">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="Math">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Algebra">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Calculus">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Geometry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Geometry">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="History">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Ancient">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Modern">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<TrailerRecord>
<A>FileA</A>
</TrailerRecord>
</FileRecord>
我得到的实际结果是
<?xml version = '1.0' encoding = 'UTF-8'?>
<FileRecord>
<HeaderRecord>
<A>FileA</A>
</HeaderRecord>
<SectionRecord Subject="Science">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Physics">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Biology">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="Math">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Geometry">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Geometry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Algebra">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Calculus">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="History">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Ancient">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Modern">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<TrailerRecord>
<A>FileA</A>
</TrailerRecord>
</FileRecord>
在 Subject=Science 部分,物理、化学和生物的顺序是正确的,但我希望 FileA 记录出现在 FileB 记录之前。在数学部分记录中,几何出现在代数和微积分之前。我希望它按 FileA 的顺序出现(并且 FileA 记录出现在 FileB 记录之前)。为什么它弄乱了数学的顺序而不是科学的顺序?
我也不喜欢使用硬编码数字来访问第一个文件记录
<xsl:apply-templates select="current-group()[1]/SectionHeader"/>
有没有更好的方法呢
我试图重现你的错误,但我的输出符合你想要的结果。
使用FileA.xml
作为第一个输入文件:
transform.xslt FileA.xml
和 FileB.xml
作为 XSLT 中的第二个输入文件:
<xsl:param name="filebrecs" select="document('FileB.xml')"/>
那么您的输出将符合预期。
尝试改变
<xsl:for-each-group select="current-group()//SectionDetails" group-by="@Stream">
<xsl:for-each select="current-group()">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:for-each-group>
至
<xsl:for-each-group select="for $rec in current-group() return $rec/SectionDetails" group-by="@Stream">
<xsl:apply-templates select="current-group()"/>
</xsl:for-each-group>
当您处理来自不同文档的节点时,使用 for return
表达式应该保留外部总体的顺序,而如果您使用 current-group()//SectionDetails
.
,则它是未定义和不可预测的
至于简化 <xsl:apply-templates select="current-group()[1]/SectionHeader"/>
,在 for-each-group
内部,每组中的第一项是上下文项,因此您可以简单地使用 .
而不是 current-group()[1]
,例如./SectionHeader
当然可以缩短为 SectionHeader
即 <xsl:apply-templates select="SectionHeader"/>
但不确定为什么要使用像 for-each-group
这样的 XSLT 2 结构,并在对其他答案的评论中提到 Xalan,它是 XSLT 1 处理器,不支持 for-each-group
。
我有两个 XML 文件,其中包含 header 部分和预告片。该部分本身有部分 header、部分详细信息和部分预告片。我需要在两个级别合并这两个文件 - 首先在部分级别,然后在部分详细信息级别。我希望我的结果基于第一个文件(Headers,预告片将来自第一个文件)。如果该部分匹配,我需要保留第一个文件中部分详细信息的顺序(没有用于排序的排序键,只有出现顺序)。如果第一个文件中没有节,我需要从第二个文件中添加整个节。
我有 xsl,它给出了结果,但顺序不正确。我需要有关如何订购它们的帮助。我没有尝试密钥查找,因为我不确定如何解释第一个文件中不存在的部分。 当 SectionDetails 匹配时,我需要第一个文件中的记录出现在第二个文件中的记录之前。
我的第一个文件 FileA 在这里
<FileRecord>
<HeaderRecord>
<A>FileA</A>
</HeaderRecord>
<SectionRecord Subject="Science">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Physics">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Biology">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="Math">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Algebra">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Calculus">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Geometry">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<TrailerRecord>
<A>FileA</A>
</TrailerRecord>
</FileRecord>
第二个文件FileB在这里
<FileRecord>
<HeaderRecord>
<A>FileB</A>
</HeaderRecord>
<SectionRecord Subject="Science">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Chemistry">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="Math">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Geometry">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="History">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Ancient">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Modern">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<TrailerRecord>
<A>FileB</A>
</TrailerRecord>
</FileRecord>
我正在使用的 xsl 在这里
<xsl:stylesheet version="2.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="xsd xsi xsl"
>
<xsl:param name="filebrecs" select="document('FileB.xml')"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="FileRecord"/>
</xsl:template>
<xsl:template match="FileRecord">
<FileRecord>
<xsl:apply-templates select="HeaderRecord"/>
<xsl:for-each-group select="SectionRecord, $filebrecs/FileRecord/SectionRecord" group-by="@Subject">
<SectionRecord>
<xsl:attribute name="Subject"><xsl:value-of select="current-grouping-key()"/> </xsl:attribute>
<xsl:apply-templates select="current-group()[1]/SectionHeader"/>
<xsl:for-each-group select="current-group()//SectionDetails" group-by="@Stream">
<xsl:for-each select="current-group()">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:for-each-group>
<xsl:apply-templates select="current-group()[1]/SectionTrailer"/>
</SectionRecord>
</xsl:for-each-group>
<xsl:apply-templates select="TrailerRecord"/>
</FileRecord>
</xsl:template>
</xsl:stylesheet>
我期待这样的结果
<FileRecord>
<HeaderRecord>
<A>FileA</A>
</HeaderRecord>
<SectionRecord Subject="Science">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Physics">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Biology">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="Math">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Algebra">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Calculus">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Geometry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Geometry">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="History">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Ancient">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Modern">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<TrailerRecord>
<A>FileA</A>
</TrailerRecord>
</FileRecord>
我得到的实际结果是
<?xml version = '1.0' encoding = 'UTF-8'?>
<FileRecord>
<HeaderRecord>
<A>FileA</A>
</HeaderRecord>
<SectionRecord Subject="Science">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Physics">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Chemistry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Biology">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="Math">
<SectionHeader>
<A>FileA</A>
</SectionHeader>
<SectionDetails Stream="Geometry">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Geometry">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Algebra">
<A>FileA</A>
</SectionDetails>
<SectionDetails Stream="Calculus">
<A>FileA</A>
</SectionDetails>
<SectionTrailer>
<A>FileA</A>
</SectionTrailer>
</SectionRecord>
<SectionRecord Subject="History">
<SectionHeader>
<A>FileB</A>
</SectionHeader>
<SectionDetails Stream="Ancient">
<A>FileB</A>
</SectionDetails>
<SectionDetails Stream="Modern">
<A>FileB</A>
</SectionDetails>
<SectionTrailer>
<A>FileB</A>
</SectionTrailer>
</SectionRecord>
<TrailerRecord>
<A>FileA</A>
</TrailerRecord>
</FileRecord>
在 Subject=Science 部分,物理、化学和生物的顺序是正确的,但我希望 FileA 记录出现在 FileB 记录之前。在数学部分记录中,几何出现在代数和微积分之前。我希望它按 FileA 的顺序出现(并且 FileA 记录出现在 FileB 记录之前)。为什么它弄乱了数学的顺序而不是科学的顺序?
我也不喜欢使用硬编码数字来访问第一个文件记录
<xsl:apply-templates select="current-group()[1]/SectionHeader"/>
有没有更好的方法呢
我试图重现你的错误,但我的输出符合你想要的结果。
使用FileA.xml
作为第一个输入文件:
transform.xslt FileA.xml
和 FileB.xml
作为 XSLT 中的第二个输入文件:
<xsl:param name="filebrecs" select="document('FileB.xml')"/>
那么您的输出将符合预期。
尝试改变
<xsl:for-each-group select="current-group()//SectionDetails" group-by="@Stream">
<xsl:for-each select="current-group()">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:for-each-group>
至
<xsl:for-each-group select="for $rec in current-group() return $rec/SectionDetails" group-by="@Stream">
<xsl:apply-templates select="current-group()"/>
</xsl:for-each-group>
当您处理来自不同文档的节点时,使用 for return
表达式应该保留外部总体的顺序,而如果您使用 current-group()//SectionDetails
.
至于简化 <xsl:apply-templates select="current-group()[1]/SectionHeader"/>
,在 for-each-group
内部,每组中的第一项是上下文项,因此您可以简单地使用 .
而不是 current-group()[1]
,例如./SectionHeader
当然可以缩短为 SectionHeader
即 <xsl:apply-templates select="SectionHeader"/>
但不确定为什么要使用像 for-each-group
这样的 XSLT 2 结构,并在对其他答案的评论中提到 Xalan,它是 XSLT 1 处理器,不支持 for-each-group
。