xml - 如何使用 xslt 减少重复元素 xml
问题描述
我有以下 XML:
<test-dump>
<table-data>
<table-max>1000</table-max>
<table>
<daten>XXXXXXXXXXXXXXXXXXXXXXXXXX
</daten>
</table>
<table>
<daten>
</daten>
</table>
<table>
<daten>
</daten>
</table>
<table>
<daten>
</daten>
</table>
<table>
<daten>
</daten>
</table>
<table>
<daten>
</daten>
</table>
<table>
<daten>
</daten>
</table>
<table>
<daten>
</daten>
</table>
<table>
<daten>
</daten>
</table>
</table-data>
<test-dump>
我想使用 XSLT 生成以下输出
转储文件为 6 G,我必须减少它 同一级别中的每个组具有相同的值 应该首先写入 2 次 使用该值第二次写入 只是从哪里到哪里 与此输出相同的上述值
table-max = 1000
table(001) =
daten = XXXXXXXXXXXXXXXXXXXXXXXXXX
table(002) =
daten =
table(003 - 009) = as above
谢谢你的帮助。
解决方案
带有 XSLT 3 和流的 Saxon EE 应该能够处理如此巨大的文件
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="text"/>
<xsl:mode on-no-match="shallow-skip" streamable="yes" use-accumulators="#all"/>
<xsl:accumulator name="table-no" as="xs:integer" streamable="yes" initial-value="0">
<xsl:accumulator-rule match="table-data" select="0"/>
<xsl:accumulator-rule match="table-data/table" select="$value + 1"/>
</xsl:accumulator>
<xsl:accumulator name="max" as="xs:integer?" streamable="yes" initial-value="()">
<xsl:accumulator-rule match="table-data/table-max/text()" select="xs:integer(.)"/>
</xsl:accumulator>
<xsl:template match="table-data">
<xsl:for-each-group select="table/daten/text()" group-adjacent=".">
<xsl:if test="position() eq 1">
<xsl:text>table-max = {accumulator-before('max')} </xsl:text>
</xsl:if>
<xsl:iterate select="current-group()">
<xsl:param name="table-no" as="xs:integer" select="0"/>
<xsl:param name="pos" as="xs:integer" select="1"/>
<xsl:on-completion select="if ($pos gt 1) then ' - ' || format-integer($table-no, '001') || ') = as above ' else ()"/>
<xsl:choose>
<xsl:when test="position() eq 1">
<xsl:text>table({format-integer(accumulator-before('table-no'), '001')}) = daten = {current-grouping-key()} </xsl:text>
</xsl:when>
<xsl:when test="position() eq 2">table({format-integer(accumulator-before('table-no'), '001')}</xsl:when>
</xsl:choose>
<xsl:next-iteration>
<xsl:with-param name="table-no" select="accumulator-before('table-no')"/>
<xsl:with-param name="pos" select="position()"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
如果您想生成 XML 输出,您可以将上面的内容更改为
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all" expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes" use-accumulators="#all"/>
<xsl:accumulator name="table-no" as="xs:integer" streamable="yes" initial-value="0">
<xsl:accumulator-rule match="table-data" select="0"/>
<xsl:accumulator-rule match="table-data/table" select="$value + 1"/>
</xsl:accumulator>
<xsl:accumulator name="max" as="xs:integer?" streamable="yes" initial-value="()">
<xsl:accumulator-rule match="table-data/table-max/text()" select="xs:integer(.)"/>
</xsl:accumulator>
<xsl:template match="table-data">
<xsl:copy>
<xsl:for-each-group select="table/daten/text()" group-adjacent=".">
<xsl:if test="position() eq 1">
<table-max>{accumulator-before('max')}</table-max>
</xsl:if>
<xsl:iterate select="current-group()">
<xsl:param name="table-start-no" as="xs:integer" select="0"/>
<xsl:param name="table-end-no" as="xs:integer" select="0"/>
<xsl:param name="pos" as="xs:integer" select="1"/>
<xsl:on-completion>
<xsl:if test="$pos gt 1">
<table range="{format-integer($table-start-no, '001')} - {format-integer($table-end-no, '001')}">
<daten>as before</daten>
</table>
</xsl:if>
</xsl:on-completion>
<xsl:if test="position() eq 1">
<table no="{format-integer(accumulator-before('table-no'), '001')}">
<daten>{current-grouping-key()}</daten>
</table>
</xsl:if>
<xsl:next-iteration>
<xsl:with-param name="table-start-no" select="if (position() eq 2) then accumulator-before('table-no') else $table-start-no"/>
<xsl:with-param name="table-end-no" select="accumulator-before('table-no')"/>
<xsl:with-param name="pos" select="position()"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如果没有流式传输,代码会更加紧凑,但我不知道它是否适用于 6 GB 输入:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all" expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-copy" use-accumulators="#all"/>
<xsl:accumulator name="table-no" as="xs:integer" initial-value="0">
<xsl:accumulator-rule match="table-data" select="0"/>
<xsl:accumulator-rule match="table-data/table" select="$value + 1"/>
</xsl:accumulator>
<xsl:template match="table-data">
<xsl:copy>
<xsl:apply-templates select="table-max"/>
<xsl:for-each-group select="table" group-adjacent="daten">
<table no="{format-integer(accumulator-before('table-no'), '001')}">
<daten>{current-grouping-key()}</daten>
</table>
<xsl:if test="tail(current-group())">
<table range="{current-group()[2] ! accumulator-before('table-no') => format-integer('001')} - {current-group()[last()] ! accumulator-before('table-no') => format-integer('001')}">
<daten>as before</daten>
</table>
</xsl:if>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
推荐阅读
- php - Laravel 5.5:文件下载 FileNotFoundException?
- azure - 适用于 Xamarin.IOS 和 Xamarin.Android 的 Azure Active Directory B2C
- r - 在R中的循环中将多列组合成一个新列
- python - 在 Python 中将列表转换为元组
- angular - 在 ag-Grid 中自定义材质主题不使用复选框的强调色
- elasticsearch - Elasticsearch 查询电影标题是否包含剧集编号
- c# - 在 EF 中使用 sql 查询
- python - 在备用列上对齐日期 Pandas Dataframe
- azure - 能否在已排序的 Azure 搜索索引中找到特定文档位置
- node.js - 用于 removeFromCollection / addToCollection 的 Sails.js 生命周期回调