cancel
Showing results for 
Search instead for 
Did you mean: 

Message Mapping - Node's sub-levels navigation

RafaelVieira
Active Participant
0 Kudos

Hi all,

How should I code in order to navigate between different levels of a given node of the source structure?

example:

Main
  Struct_11
    Struct1101
      Field_1101_A
      Field_1101_B
    Struct1102
      Field_1102_A
      Field_1102_B
  Struct_22
    Struct2201
      Field_2201_A
      Field_2201_B
    Struct2202
      Field_2202_A
      Field_2202_B

In the sample above, how should I do to map the node Struct_11 and, within a UDF (or some other way, but I only imagine through a Java UDF), access and validate Struct1101-Field_1101_A, or Struct1102-Field_1102_B, etc?

If someone could provide me with a sample code, it'd help me.

Thank you!

Accepted Solutions (1)

Accepted Solutions (1)

markangelo_dihiansan
Active Contributor
0 Kudos

Hello,

how should I do to map the node Struct_11 and, within a UDF (or some other way, but I only imagine through a Java UDF

In your message mapping editor, right-click Struct_11(same as what you do to set contexts) and then select Return As XML, from there, you can pass it into a UDF within the mapping.

Hope this helps,

Mark

RafaelVieira
Active Participant
0 Kudos

Mark, tks. It helped.

I could do all that I needed withing the XML working as a text.

The only problem now is that, the target structure must be built according to the source cardinality (N..N).

In the sample bellow, see that in the source structure, the Struct_11 repeat 3 times. In the 1st and 3rd, it contains the substructure Struct1101. I have to check if Struct1101 exists, if so, I have to take the Field_1101_A and validate if it's equal to WE. If yes, then the correspondent Field_1101_B has to be sent to target <row> field.

In the 2nd occurrence, there NO Struct1101, so the UDF returns #void#.

UDF to map Struct_11:

int v_pos1, v_pos2, v_start = 0;
String v_Struct1101 = "Struct1101";
String v_WE = "WE";
String v_FieldA = "<Field_1101_A>WE</Field_1101_A>";
String v_FieldB = "";

v_pos1 = Item.indexOf(v_Struct1101);
if(v_pos1 >= 0){
	v_pos2 = Item.indexOf(v_FieldA);
	v_start = v_pos2 + 32;
	v_FieldB = Item.substring(v_start, v_start+10);
}else{
		v_FieldB = "#void#";
}
return v_FieldB;

Source


<Main>
  <Struct_11>
    <Struct1101>
      <Field_1101_A>WE</Field_1101_A>
      <Field_1101_B>110</Field_1101_B>
    </Struct1101>
    <Struct1102>
      <Field_1102_A>ZS</Field_1102_A>
      <Field_1102_B>222</Field_1102_B>
    </Struct1102>
  </Struct_11>
  <Struct_11>
    <Struct1102>
      <Field_1102_A>ZS</Field_1102_A>
      <Field_1102_B>222</Field_1102_B>
    </Struct1102>
  </Struct_11>
  <Struct_11>
    <Struct1101>
      <Field_1101_A>WE</Field_1101_A>
      <Field_1101_B>112</Field_1101_B>
    </Struct1101>
    <Struct1102>
      <Field_1102_A>ZS</Field_1102_A>
      <Field_1102_B>222</Field_1102_B>
    </Struct1102>
  </Struct_11>
  <Struct_22>
    <Struct2201>
      </Field_2201_A>
      </Field_2201_B>
    <Struct2202>
      </Field_2202_A>
      </Field_2202_B>
</Main>

Target

<result>
  <row>110</row></result>
<result>
  <row>#void#</row></result>
<result>  <row>112</row></result>

<result> is mapped to <Struct_11>, so that for each <Struct_11>, one <result> is created.

I've insert this sample payload and in the Definition tab, Display Queue option shows me the right result:

110

#void#

112

However, during the MM test, it throws error:

Cannot create target element /ns0:MT_TARGET/result[2]/row. Values missing in queue context. Target XSD requires a value for this element, but the target-field mapping does not create one. Check whether the XML instance is valid for the source XSD, and whether the target-field mapping fulfils the requirement of the target XSD

Any clue?

Thank you !

Edited by: rvsilvax on Sep 14, 2011 9:00 PM

markangelo_dihiansan
Active Contributor
0 Kudos

Hello,

I could do all that I needed withing the XML working as a text.

The only problem now is that, the target structure must be built according to the source cardinality (N..N).

The easiest and fastest to implement solution would be to go for a two-step mapping in your operation mapping. For the first mapping, your source and target structures are the same, but you add the node function mapWithDefault for the fields that you are checking e.g


v_FieldB -> mapWithDefault -> v_FieldB

This will ensure that v_FieldB will always be existing. The second mapping is the actual mapping (the one with return as xml).

Hope this helps,

Mark

Answers (2)

Answers (2)

Former Member
0 Kudos

Hi,

I feel, there is one more better option to go for XSLT mapping.

XSLT mapping is easy to navigate the different levels of the node of source structure.

Best Regards,

Sateesh

RafaelVieira
Active Participant
0 Kudos

I'll try to find something about XSLT mapping.

I'm still facing some problems in this mapping, but this error was fixed by sending the tag as XML and performing some Java substrings.

Tks!

anupam_ghosh2
Active Contributor
0 Kudos

Hi,

you need java mapping to meet your requirement. With DOM parser you can reach any node in the the source XML and map onto a target XML. You have not mentioned the target XML structure,mapping requirements and version of PI you working on.

Still you can refer to following articles/blogs for java mapping

http://wiki.sdn.sap.com/wiki/display/XI/ParametrizedJavaMappinginPI+7.1

http://wiki.sdn.sap.com/wiki/display/XI/BeginnersguidetoJavamappingusingDOMparserinSAPXI

regards

Anupam

RafaelVieira
Active Participant
0 Kudos

Tks Anupam.

We're running PI 7.1.

Regarding the target structure, I didn't mention because it's just a single field which must receive the result of this validation.

By the source structure I provided before, I have to mapp a main node and perform some validations in its child nodes and fields. As soon as it's validated, I'll take the corresponding field content and map to target.

Using the same example:

I'd give the <Struct_11> as the input parameter (as it contains all subnodes I need to the validations).

My Java UDF should check:

if(Struct1101-Field_1101_A == 'TCB')
{
   target-field1 = Field_1101_B.
}elseif(Struct1102-Field_1102_A == 'TCB')
{
   target-field1 = Field_1102_B.
}

I need it to be done in a UDF.

Tks.

anupam_ghosh2
Active Contributor
0 Kudos

Hi,

Thank you for the explanation. I have a small request , please mention all your requirements and explain them properly when you are posting in forum. By this you ensure correct answers and quick response.

Now as per your requirement, this is better done using java mapping. If you want to use only UDF try this

using message mapping for each Struct11***



Field_1101_A---------->remove context  (this is input String a[] to UDF)
Field_1101_B---------->remove context   (this is input String b[] to UDF)
                                                        ------>UDF ------> target-field1
Field_1102_A---------->remove context  (this is input String c[] to UDF)
Field_1102_B---------->remove context  (this is input String d[] to UDF)


The UDF is advanced UDF using UDF type="context" as per this link http://help.sap.com/saphelp_nw04/helpdata/en/22/e127f28b572243b4324879c6bf05a0/content.htm.

Now the UDF to be written is shown below


public void MapValues(String[] a,String[] b,String[] c,String[] d,ResultList result,Container container){

String s="TCB";

       if(a[0]!=null && a[0].equals(s))
       {
              result.addValue(b[0]);
       }
       else if( c[0]!=null && c[0].equals(s))
       {
               result.addValue(d[0]);
       }



}

Hope this helps.

Just did a little change to the UDF.

regards

Anupam

Edited by: anupamsap on Sep 13, 2011 9:01 PM