Reputation: 1368
I have two XSLT workflows: Full (XSLT2) and Incremental (XSLT3).
Below full3.xml
is the merge & split result of Full
workflow:
<Account>
<metadata>
<_uri>full3.xml</_uri>
<created>2020-11-26T23:16:08.076-07:00</created>
<lastModified>2020-11-26T23:16:08.076-07:00</lastModified>
<merge-lineage>
<merged-uri>lot960151-3.xml</merged-uri>
<merged-uri>lot860150-3.xml</merged-uri>
</merge-lineage>
</metadata>
<accountPersistentID>51b10faa</accountPersistentID>
<accountID>ACC300</accountID>
<accountName>bonafide-3</accountName>
<Item>
<contract>
<amount>
<currency>USD</currency>
<amount>5000000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>4000000.00</amount>
</amount>
</contract>
</Item></Account>
I have subsequent incremental input XMLs to be matched & (if matched) merged; if no match, then transform it as above similar structure.
lot660152-3.xml
is the raw document structure. The match & merge criteria are the accountId
and accountName
<ContractServicing>
<account id="ACC3">
<accountId>ACC300</accountId>
<accountName>bonafide-3</accountName>
<accountBeneficiary href="party5"/>
<servicingParty href="party6"/>
</account>
<contract>
<amount>
<currency>USD</currency>
<amount>5700000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>4000000.00</amount>
</amount>
</contract></ContractServicing>
The desired results of the Incremental
XSLT workflow should be:
lot660152-3.xml
is matched and its each contract
shall be merged into Item
element in full3.xml
(NOTE: _uri
is generated during the Full
workflow and can be changed during the incremental
workflow. But the accountPersistentID
generated during the Full
workflow shall be untouched. Also lastModified
and merged-uri
shall be updated if any merge event. <Account>
<metadata>
<_uri>full3.xml</_uri>
<created>2020-11-26T23:16:08.076-07:00</created>
<lastModified>2020-11-29T00:00:00.000-00:00</lastModified>
<merge-lineage>
<merged-uri>lot960151-3.xml</merged-uri>
<merged-uri>lot860150-3.xml</merged-uri>
<merged-uri>lot660152-3.xml</merged-uri>
</merge-lineage>
</metadata>
<accountPersistentID>51b10faa</accountPersistentID>
<accountID>ACC300</accountID>
<accountName>bonafide-3</accountName>
<Item>
<contract>
<amount>
<currency>USD</currency>
<amount>5000000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>4000000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>5700000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>4000000.00</amount>
</amount>
</contract>
</Item>
</Account>
Incremental
workflow shall create a new document similar to full3.xml
for no-matched raw document.As it currently stands, I am pleased with Full
workflow but I can’t seem to get any line on XSLT3 merge
instruction during the Incremental
workflow.
My XSLT
Incremental
workflow
<xsl:template match="/">
<xsl:merge>
<xsl:merge-source name="full" streamable="yes" for-each-source="$full-docs" select="Account">
<xsl:merge-key select="accountID"/>
</xsl:merge-source>
<xsl:merge-source name="incremental" for-each-source="$incre-docs" select="ContractServicing">
<xsl:merge-key select="account/accountId"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:choose>
<xsl:when test="current-merge-group('incremental')/account/accountId = current-merge-group('full')/accountID">
<xsl:apply-templates select="current-merge-group('full')"/>
<xsl:for-each select="current-merge-group('full')/Item">
<xsl:copy-of select="current-merge-group('incremental')/contract"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-merge-group('incremental')" />
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
</xsl:merge>
</xsl:template>
The result is none of the matched incremental contract
merged into Item
and the no-match document has not been transformed. (This has been resolved by Michael Kay)
Null Pointer
Upvotes: 0
Views: 194
Reputation: 163595
I added some boilerplate:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
expand-text="yes"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="merge-contracts" on-no-match="shallow-copy"/>
<xsl:mode name="unmatched" on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
and then changed the xsl:merge-action
to
<xsl:merge-action>
<xsl:choose>
<xsl:when test="current-merge-group('incremental')/account/accountId = current-merge-group('full')/accountID">
<xsl:apply-templates select="current-merge-group('full')" mode="merge-contracts">
<xsl:with-param name="extra" select="current-merge-group('incremental')"
tunnel="yes" as="element(ContractServicing)"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-merge-group('incremental')" mode="unmatched"/>
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
so if there's a match, it's processing the main document in mode merge-contracts with the incremental document passed in a tunnel parameter; and if there's no match, it's processing the incremental document in mode "unmatched".
The merged-contracts
mode has three template rules:
<xsl:template match="lastModified/text()" mode="merge-contracts">
<xsl:value-of select="current-dateTime()"/>
</xsl:template>
<xsl:template match="merge-lineage" mode="merge-contracts">
<xsl:param name="extra" tunnel="yes" as="element(ContractServicing)"/>
<xsl:copy>
<xsl:copy-of select="*"/>
<merged-uri>{
tokenize($extra/root()/document-uri(),'/')[last()]
}</merged-uri>
</xsl:copy>
</xsl:template>
<xsl:template match="Item" mode="merge-contracts">
<xsl:param name="extra" tunnel="yes" as="element(ContractServicing)"/>
<xsl:copy>
<xsl:copy-of select="*, $extra//contract"/>
</xsl:copy>
</xsl:template>
which might not do everything you want to do, but I think it captures the essence.
Where the incremental document isn't matched, it becomes a very routine transformation which I approximated with:
<xsl:template match="ContractServicing" mode="unmatched">
<xsl:result-document href="unmatched.xml">
<Account>
<metadata>...</metadata>
<accountPersistentID>...</accountPersistentID>
<xsl:copy-of select="//contract"/>
</Account>
</xsl:result-document>
</xsl:template>
I'm not really sure where your difficulties arose. Your code refers to an "item" element that doesn't exist; and you didn't show us any code for combining the merge-lineage element or for merging the contracts. I don't know if that's because you had no problems with this code, or because you didn't know how to go about writing it.
Upvotes: 1