Как реструктурировать XML с помощью XSLT, когда дочерний узел на самом деле является родительским
У меня очень плохо структурированный XML-источник, выходящий из нашей системы ERP, и отношение Родитель / Дочерний для заголовка к деталям меняется на обратное, потому что во время выполнения родительский (ключ) не известен до тех пор, пока не будет обработана первая подробная запись. Это связано с тем, как был написан интерфейс из старого приложения DB2 для мэйнфреймов. К сожалению, я не имею права вносить изменения в отчет, и при этом я не имею никакого влияния на изменение отчета, поэтому мне приходится иметь дело с источником как есть.
Вот как выглядит вывод XML:
<report>
<detail>
<header>
<keyfield>1231</keyfield>
<headerfield1>foo</headerfield>
<headerfield2>bar</headerfield2>
</header>
<keymatch>1231</keymatch>
<detailfield0>Line1</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line2</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line3</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line4</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line5</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<header>
<keyfield>1232</keyfield>
<headerfield1>boo</headerfield>
<headerfield2>far</headerfield2>
</header>
<keymatch>1232</keymatch>
<detailfield0>Line1</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line2</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line3</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line4</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line5</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
</report>
В конечном итоге мне нужно, чтобы он был в формате, подобном следующему:
<report>
<header>
<keyfield>1231</keyfield>
<headerfield1>foo</headerfield>
<headerfield2>bar</headerfield2>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line1</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line2</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line3</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line4</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1231</keymatch>
<detailfield0>Line5</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
</header>
<header>
<keyfield>1232</keyfield>
<headerfield1>boo</headerfield>
<headerfield2>far</headerfield2>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line1</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line2</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line3</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line4</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
<detail>
<keymatch>1232</keymatch>
<detailfield0>Line5</detailfield0>
<detailfield1>this is bad structure</detailfield1>
<detailfield2>and not my design</detailfield2>
</detail>
</header>
</report>
По общему признанию, я не знаю много о XSLT, но я быстро изучаю, и я понял, что это инструмент, который мне нужно использовать. Что бы это ни стоило, это JD Edwards 9.1, и я буду использовать BI Publisher для отправки данных через шаблон XSL для дальнейшей передачи партнерам по EDI.
Спасибо,
Джастин
1 ответ
Попробуйте это так:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/report">
<xsl:copy>
<xsl:for-each-group select="detail" group-starting-with="detail[header]">
<header>
<xsl:copy-of select="header/*"/>
<xsl:apply-templates select="current-group()"/>
</header>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="detail">
<xsl:copy>
<xsl:copy-of select="* except header"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>