如何使用 java xslt 将数据从一个 xml 文件复制到另一个文件
how to copy data from one xml files in to another using java xslt
- 我需要全部更换吗?在 file1.xml 中,元素值存在于 File2.xml.
中
- 并且还需要删除 File1.xml 中存在的额外元素节点,其值不存在于 File2.xml 中。 (即在我的示例输入中,需要从 file1.xml 中删除 totalDueWithoutTax 元素,因为它不存在于 File2.xml.
中
- 可能有这样的情况,我们在 File2 中有多个元素,但在 File1 中只有一个对应的元素。就像在我下面的示例中一样,我们在 File2 中有两个 salesInfo 元素,但在 File1 中我们只有一个。在这种情况下,作为预期输出,我们需要 File2.
的 salesInfo 元素
- 这只是示例输入。在实际场景中,输入的 xml 可能不同,这意味着我们每次都可以获得不同格式的 xml。
请在 java 中建议我如何做到这一点。如果能用xslt实现就更好了。
**File 1 -- input xml**
<order>
<orderId>?</orderId>
<sales>
<salesInfo>
<salesChannel>?</salesChannel>
<senderSystemId>?</senderSystemId>
<applicationId>?</applicationId>
<totalDueWithoutTax>?</totalDueWithoutTax>
</salesInfo>
<salesid>?</salesid>
</sales>
</order>
**File 2 -- input xml**
<order>
<orderId>4567</orderId>
<sales>
<salesInfo>
<salesChannel>abc</salesChannel>
<senderSystemId>def</senderSystemId>
<applicationId>123</applicationId>
<esignatureCaptureMode>INLINE</esignatureCaptureMode>
</salesInfo>
<salesInfo>
<salesChannel>xyz</salesChannel>
<senderSystemId>uvw</senderSystemId>
<applicationId>234</applicationId>
<esignatureCaptureMode>outline</esignatureCaptureMode>
</salesInfo>
<salesid>789</salesid>
</sales>
</order>
**Expected output:**
<order>
<orderId>4567</orderId>
<sales>
<salesInfo>
<salesChannel>abc</salesChannel>
<senderSystemId>def</senderSystemId>
<applicationId>123</applicationId>
</salesInfo>
<salesInfo>
<salesChannel>xyz</salesChannel>
<senderSystemId>uvw</senderSystemId>
<applicationId>234</applicationId>
</salesInfo>
<salesid>789</salesid>
</sales>
</order>
你可以考虑一个group/merge问题:
<?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"
xmlns:mf="http://example.com/mf"
expand-text="yes">
<xsl:param name="doc2" select="doc('file2.xml')"/>>
<xsl:output method="xml" indent="yes"/>
<xsl:function name="mf:merge" as="node()*">
<xsl:param name="nodes1" as="node()*"/>
<xsl:param name="nodes2" as="node()*"/>
<xsl:for-each-group select="$nodes1, $nodes2" group-by="node-name()">
<xsl:choose>
<xsl:when test="not(*) and . = '?' and current-group()[2]">
<xsl:apply-templates select="current-group()[2]"/>
</xsl:when>
<xsl:when test="current-group()[1][*] and current-group()[2][*]">
<xsl:copy>
<xsl:sequence select="mf:merge(*, current-group()[2]/*)"/>
</xsl:copy>
</xsl:when>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="/*">
<xsl:copy>
<xsl:sequence select="mf:merge(*, $doc2/*/*)"/>
</xsl:copy>
</xsl:template>
<xsl:mode on-no-match="shallow-copy"/>
</xsl:stylesheet>
根据结构或合并要求,使用 xsl:for-each-group select="$nodes1, $nodes2" group-by="path(.)"
而不是 <xsl:for-each-group select="$nodes1, $nodes2" group-by="node-name()">
可能更合适,例如,如果一个元素可以有多个同名的子元素。
一个“开箱即用”的建议:您可能希望将 file1 视为代表一种小型模板语言。如果您这样想,那么想到的一个选择是将您的小模板语言翻译成 XSLT(当然,可以使用 XSLT 完成的翻译)。
所以你的转换会转换
<salesChannel>?</salesChannel>
至
<salesChannel>
<xsl:value-of select="order/salesinfo/saleschannel"/>
</salesChannel>
其中select属性中的表达式是通过调用path()
获得的。
这种方法的优点是您可以开始发展您的“小模板语言”以包含额外的功能,如出现要求时的循环和条件。
- 我需要全部更换吗?在 file1.xml 中,元素值存在于 File2.xml. 中
- 并且还需要删除 File1.xml 中存在的额外元素节点,其值不存在于 File2.xml 中。 (即在我的示例输入中,需要从 file1.xml 中删除 totalDueWithoutTax 元素,因为它不存在于 File2.xml. 中
- 可能有这样的情况,我们在 File2 中有多个元素,但在 File1 中只有一个对应的元素。就像在我下面的示例中一样,我们在 File2 中有两个 salesInfo 元素,但在 File1 中我们只有一个。在这种情况下,作为预期输出,我们需要 File2. 的 salesInfo 元素
- 这只是示例输入。在实际场景中,输入的 xml 可能不同,这意味着我们每次都可以获得不同格式的 xml。
请在 java 中建议我如何做到这一点。如果能用xslt实现就更好了。
**File 1 -- input xml**
<order>
<orderId>?</orderId>
<sales>
<salesInfo>
<salesChannel>?</salesChannel>
<senderSystemId>?</senderSystemId>
<applicationId>?</applicationId>
<totalDueWithoutTax>?</totalDueWithoutTax>
</salesInfo>
<salesid>?</salesid>
</sales>
</order>
**File 2 -- input xml**
<order>
<orderId>4567</orderId>
<sales>
<salesInfo>
<salesChannel>abc</salesChannel>
<senderSystemId>def</senderSystemId>
<applicationId>123</applicationId>
<esignatureCaptureMode>INLINE</esignatureCaptureMode>
</salesInfo>
<salesInfo>
<salesChannel>xyz</salesChannel>
<senderSystemId>uvw</senderSystemId>
<applicationId>234</applicationId>
<esignatureCaptureMode>outline</esignatureCaptureMode>
</salesInfo>
<salesid>789</salesid>
</sales>
</order>
**Expected output:**
<order>
<orderId>4567</orderId>
<sales>
<salesInfo>
<salesChannel>abc</salesChannel>
<senderSystemId>def</senderSystemId>
<applicationId>123</applicationId>
</salesInfo>
<salesInfo>
<salesChannel>xyz</salesChannel>
<senderSystemId>uvw</senderSystemId>
<applicationId>234</applicationId>
</salesInfo>
<salesid>789</salesid>
</sales>
</order>
你可以考虑一个group/merge问题:
<?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"
xmlns:mf="http://example.com/mf"
expand-text="yes">
<xsl:param name="doc2" select="doc('file2.xml')"/>>
<xsl:output method="xml" indent="yes"/>
<xsl:function name="mf:merge" as="node()*">
<xsl:param name="nodes1" as="node()*"/>
<xsl:param name="nodes2" as="node()*"/>
<xsl:for-each-group select="$nodes1, $nodes2" group-by="node-name()">
<xsl:choose>
<xsl:when test="not(*) and . = '?' and current-group()[2]">
<xsl:apply-templates select="current-group()[2]"/>
</xsl:when>
<xsl:when test="current-group()[1][*] and current-group()[2][*]">
<xsl:copy>
<xsl:sequence select="mf:merge(*, current-group()[2]/*)"/>
</xsl:copy>
</xsl:when>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="/*">
<xsl:copy>
<xsl:sequence select="mf:merge(*, $doc2/*/*)"/>
</xsl:copy>
</xsl:template>
<xsl:mode on-no-match="shallow-copy"/>
</xsl:stylesheet>
根据结构或合并要求,使用 xsl:for-each-group select="$nodes1, $nodes2" group-by="path(.)"
而不是 <xsl:for-each-group select="$nodes1, $nodes2" group-by="node-name()">
可能更合适,例如,如果一个元素可以有多个同名的子元素。
一个“开箱即用”的建议:您可能希望将 file1 视为代表一种小型模板语言。如果您这样想,那么想到的一个选择是将您的小模板语言翻译成 XSLT(当然,可以使用 XSLT 完成的翻译)。
所以你的转换会转换
<salesChannel>?</salesChannel>
至
<salesChannel>
<xsl:value-of select="order/salesinfo/saleschannel"/>
</salesChannel>
其中select属性中的表达式是通过调用path()
获得的。
这种方法的优点是您可以开始发展您的“小模板语言”以包含额外的功能,如出现要求时的循环和条件。