1
  1. I need to replace all ? in file1.xml with element value present in File2.xml.
  2. And also need to remove extra element node present in File1.xml whose value is not present in File2.xml. (i.e. In my sample input need to remove totalDueWithoutTax element from file1.xml as it is not present in File2.xml.
  3. There may be the cases where we have multiple elements in File2 but only one corresponsing element in File1. Like in my below example we have two salesInfo element in File2 but in File1 we have only one. In that case as a expected output we need both salesInfo element of File2.
  4. This is just sample input. In real scenario input xmls can be different means we can get different format of xmls everytime.

Please suggest me how to do that in java. It would be better if we can achieve this using 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>
4
  • All the input comes from file2 and even the tag names are the same. What do you need file1 for? Commented Feb 7, 2022 at 9:47
  • Will the structure of the two documents always be as shown (i.e. order root element in the first document, root root element) in the second, and you know an order root element in the first document is matched against that root root element in the second document? Commented Feb 7, 2022 at 9:48
  • @f1sh these are not exactly same. file1 have totalDueWithoutTax element and file 2 have esignatureCaptureMode element. In my expected output i don't want these element. Commented Feb 7, 2022 at 9:50
  • @MartinHonnen i have edited my question. Root element will always be order in both file1 and file2 Commented Feb 7, 2022 at 9:53

2 Answers 2

2

An "out of the box" suggestion: you might like to think of your file1 as representing a little templating language. If you think of it that way, then one option that comes to mind is to translate your little templating language into XSLT (a translation which, of course, can be done using XSLT).

So your transformation would convert

<salesChannel>?</salesChannel>

to

<salesChannel>
      <xsl:value-of select="order/salesinfo/saleschannel"/>
</salesChannel>

where the expression in the select attribute is obtained by calling path().

The advantage of this approach is that you can start to grow your "little templating language" to include extra features, such as loops and conditionals, as the requirements appear.

Sign up to request clarification or add additional context in comments.

Comments

0

You could consider a group/merge problem:

<?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>

Depending on the structure or the merging requirements using xsl:for-each-group select="$nodes1, $nodes2" group-by="path(.)" instead of <xsl:for-each-group select="$nodes1, $nodes2" group-by="node-name()"> might be more suitable, for instance if an element can have several child elements of the same name.

4 Comments

Thank you very much for the reply. It is failing in one scenario. If we have multiple <salesInfo> nodes in File2, but File1 have only one <salesInfo> node. In my expected output ... i want all <salesInfo> nodes from File2 but attributes should be common only. Please help me on that.
@ankushgarg, consider to edit your question and show samples for that more complicated setting with multiple salesInfo elements in file 2 but only one in file 1, together with the exact output you want for that sample case.
I have edited the question. For better clarity i have put the <salesInfo> element under <sales>. Please refer to my point number 3.
@ankushgarg, I have read through your edit but with the new requirement a merging/grouping based on node name or exact XPath, as my two suggestions attempted, can't work as the several elements in the second document have no counterpart for the grouping with the items from the first document. So I am afraid there is no easy adaption of the given answer to the new requirement. I will leave the answer as it is, perhaps it can serve you as an idea how to work out something on your own with XSLT for your more complicated requirements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.