gpt4 book ai didi

xml - 使用 XSLT 对 XML 转换中的元素进行分组

转载 作者:数据小太阳 更新时间:2023-10-29 01:54:48 25 4
gpt4 key购买 nike

我正在为使用 XSLT 将基于表的 XML 分组(在多个键上)到层次结构的概念而苦苦挣扎

分组基于前四个元素,但是如果集合之间有另一个元素,则分组必须中断。

源 XML:

<RECORDS> 
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F1>A1</F1>
</RECORD>
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F1>A2</F1>
</RECORD>
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>195</E5>
<F1>A3</F1>
</RECORD>
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F1>A4</F1>
</RECORD>
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F1>A5</F1>
</RECORD>
<RECORD>
<E1>DONALD</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F1>A6</F1>
</RECORD>
<RECORD>
<E1>DONALD</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F1>A7</F1>
</RECORD>
</RECORDS>

输出 XML

 <RECORDS>
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F>
<F1>A1</F1>
<F1>A2</F1>
</F>
</RECORD>
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>195</E5>
<F>
<F1>A3</F1>
<F1>A4</F1>
</F>
</RECORD>
<RECORD>
<E1>MICKEY</E1> <!--Must break and not merge in first group -->
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F>
<F1>A5</F1>
</F>
</RECORD>
<RECORD>
<E1>DONALD</E1>
<E2>TEST</E2>
<E4>14</E4>
<E5>196</E5>
<F>
<F1>A6</F1>
<F1>A7</F1>
</F>
</RECORD>
</RECORDS>

这是我到目前为止提出的 XSL...

<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="grouped" match="RECORD"
use="concat(E1, '+', E2, '+', E4 , '+', E5 )"/>

<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<RECORDS>
<xsl:apply-templates select=
"RECORD[generate-id()
=
generate-id(key('grouped',
concat(E1, '+', E2, '+', E4 , '+', E5 )
)
[1]
)
]
"/>
</RECORDS>
</xsl:template>
<xsl:template match="RECORD">
<RECORD>
<E1><xsl:value-of select="E1"/></E1>
<E2><xsl:value-of select="E2"/></E2>
<E4><xsl:value-of select="E4"/></E4>
<F>
<xsl:for select="F1">
<F1><xsl:value-of select="F1"/></F1>
</xsl:for>

</F>
</RECORD>

</xsl:template>
</xsl:stylesheet>

问题是我无法为每个 f1 生成重复的内部标签。另外,我应该得到 4 套记录,而不是我得到的 3 套。

<RECORDS>
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<F></F>
</RECORD>
<RECORD>
<E1>MICKEY</E1>
<E2>TEST</E2>
<E4>14</E4>
<F></F>
</RECORD>
<RECORD>
<E1>DONALD</E1>
<E2>TEST</E2>
<E4>14</E4>
<F></F>
</RECORD>
</RECORDS>

最佳答案

这是一个使用 key 的解决方案更短(代码行数减少 28%,并且不需要水平滚动)。 更健壮(有关详细信息,请参阅此答案的末尾)

它更通用,因为即使在我们想要分组的元素之间,还有其他必须忽略的元素(即 preceding-sibling::*[1] 可能是我们想要从中排除的元素)的情况下,它也会起作用分组——在当前问题中——不是 RECORD 元素):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:key name="kStartGroup" match="/*/*" use=
"generate-id(preceding-sibling::*
[not(concat(E1, '|', E2, '|', E4, '|', E5)
= concat(current()/E1, '|', current()/E2, '|', current()/E4, '|', current()/E5)
)
][1])"/>
<xsl:template match="*[not(concat(E1, '|', E2, '|', E4, '|', E5)
=
concat(preceding-sibling::*[1]/E1, '|',
preceding-sibling::*[1]/E2, '|',
preceding-sibling::*[1]/E4, '|',
preceding-sibling::*[1]/E5)
)]">
<xsl:copy>
<xsl:copy-of select="E1 | E2 | E4 | E5"/>
<F><xsl:copy-of select=
"key('kStartGroup', generate-id(preceding-sibling::*[1]))/F1"/></F>
</xsl:copy>
</xsl:template>
<xsl:template match="/*"><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>

稳健性/可扩展性

因为此转换不包含递归(对 <xsl:apply-templates 的嵌套调用),所以在应用于大型 XML 文件时它是健壮且可扩展的。

另一方面,当对足够大的 XML 文档应用转换时,另一个答案“siblings recursion”中提供的解决方案由于堆栈溢出而崩溃。在我的例子中,这个崩溃是在大约 13,000(13,000 行)的源 XML 文档中观察到的——这可能因可用的 RAM、XSLT 处理器等而异。

当前的转换即使在非常大的 XML 文档上也能成功执行——例如有 1200000(100 万和 200000 行)。

关于xml - 使用 XSLT 对 XML 转换中的元素进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37048741/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com