Java, Programming

Java Use Top Down Method and JAX-WS to Develop Web Service Provider

java-use-top-down-method-and-jax-ws-to-develop-web-service-provider

I have been talk about Bottom up method. In this post, I will talk about Top Down method to deploy Web Service.

Using Top Down method, you must have a knowledge in XML Schema and Web Services Description Language. If you do not have those knowledge, please follow the URL to learn about that.

XML Schema: http://www.w3schools.com/schema/default.asp
Web Services Description Language: http://www.w3schools.com/WSDL/default.asp

In this tutorial, I will simulate a employee lookup service. Client send a list of employee to service provider. Service provider lookup an employee info and return a list of info to client.

When creating a Web service using a top-down approach, first you design the implementation of the Web service by creating a WSDL file. You can do this using the WSDL Editor. You can then use the Web services wizard to create the Web service and skeleton Java™ classes to which you can add the required code.

First, you need create a WAR project in Eclipse, NetBeans or other IDE. Add 2 file in web root – company.xsd and company.wsdl.

company.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.memorylack.com/company" xmlns:tns="http://www.memorylack.com/company"
  elementFormDefault="qualified">
  <xs:simpleType name="EmployeeId">
    <xs:restriction base="xs:string">
      <xs:length value="7" />
      <xs:pattern value="E[0-9]{7}" />
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="EmployeeTitle">
    <xs:restriction base="xs:string">
      <xs:enumeration value="CEO" />
      <xs:enumeration value="Manger" />
      <xs:enumeration value="Supervisor" />
      <xs:enumeration value="Clerk" />
    </xs:restriction>
  </xs:simpleType>

  <xs:complexType name="EmployeeInfo">
    <xs:sequence>
      <xs:element name="eid" type="tns:EmployeeId"
        minOccurs="0" nillable="false" />
      <xs:element name="firstName" type="xs:string"
        minOccurs="0" nillable="false" />
      <xs:element name="lastName" type="xs:string"
        minOccurs="0" nillable="false" />
      <xs:element name="age" type="xs:unsignedShort"
        minOccurs="0" nillable="false" />
      <xs:element name="title" type="tns:EmployeeTitle"
        minOccurs="0" nillable="false" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="EmployeeInfoWrapper">
    <xs:sequence>
      <xs:element name="employeeInfo" type="tns:EmployeeInfo"
        minOccurs="0" maxOccurs="unbounded" nillable="false" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="EmployeeIdWrapper">
    <xs:sequence>
      <xs:element name="eid" type="tns:EmployeeId"
        minOccurs="0" maxOccurs="unbounded" nillable="false" />
    </xs:sequence>
  </xs:complexType>

  <xs:element name="EmployeeIdList" type="tns:EmployeeIdWrapper" />
  <xs:element name="EmployeeInfoList" type="tns:EmployeeInfoWrapper" />

</xs:schema>

company.wsdl:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="Company" targetNamespace="http://www.memorylack.com/company"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.memorylack.com/company"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
    <xsd:schema>
      <xsd:import namespace="http://www.memorylack.com/company"
        schemaLocation="company.xsd" />
    </xsd:schema>
  </wsdl:types>

  <wsdl:message name="employeeLookupRequest">
    <wsdl:part element="tns:EmployeeIdList" name="employeeIdList" />
  </wsdl:message>

  <wsdl:message name="employeeLookupResponse">
    <wsdl:part element="tns:EmployeeInfoList" name="employeeInfoList" />
  </wsdl:message>

  <wsdl:portType name="employeeLookupService">
    <wsdl:operation name="employeeLookup">
      <wsdl:input message="tns:employeeLookupRequest" />
      <wsdl:output message="tns:employeeLookupResponse" />
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="employeeLookupBinding" type="tns:employeeLookupService">
    <soap:binding style="document"
      transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="employeeLookup">
      <soap:operation
        soapAction="http://www.memorylack.com/company/employeeLookup" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

  <wsdl:service name="employeeLookupService">
    <wsdl:port binding="tns:employeeLookupBinding" name="employeeLookupPort">
      <soap:address location="http://localhost" />
    </wsdl:port>
  </wsdl:service>

</wsdl:definitions>

you have complete web service interface, but you need create a corresponding Java class. We use JAXB compiler to transfer XML Schema complex type to Java object. Open the CMD.exe to enter below command:

xjc -wsdl company.wsdl -p com.memorylack.www.ws.model

**If Windows alert you xjc not found, Please add %JAVA_HOME%/bin to system path. default %JAVA_HOME% is: C:Program FilesJavajdk1.6.0_21bin**

  • -wsdl option is set your WSDL location
  • -p is set generated Java class package

More option can be found in: JAXB Using

After enter command. You can see following .java file.

  1. EmployeeIdWrapper
  2. EmployeeInfo
  3. EmployeeInfoWrapper
  4. EmployeeTitle
  5. ObjectFactory
  6. package-info

EmployeeIdWrapper:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.06.23 at 04:28:35 PM CST 
//
package com.memorylack.www.ws.model;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for EmployeeIdWrapper complex type.
 *
 * <p>The following schema fragment specifies the expected content contained within this class.
 *
 * <pre>
 * &lt;complexType name="EmployeeIdWrapper">
 * &lt;complexContent>
 * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 * &lt;sequence>
 * &lt;element name="eid" type="{http://www.memorylack.com/company}EmployeeId" maxOccurs="unbounded" minOccurs="0"/>
 * &lt;/sequence>
 * &lt;/restriction>
 * &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EmployeeIdWrapper", propOrder = {
    "eid"
})
public class EmployeeIdWrapper {

  protected List<String> eid;

  /**
   * Gets the value of the eid property.
   *
   * <p>
   * This accessor method returns a reference to the live list,
   * not a snapshot. Therefore any modification you make to the
   * returned list will be present inside the JAXB object.
   * This is why there is not a <CODE>set</CODE> method for the eid property.
   *
   * <p>
   * For example, to add a new item, do as follows:
   * <pre>
   * getEid().add(newItem);
   * </pre>
   *
   *
   * <p>
   * Objects of the following type(s) are allowed in the list
   * {@link String }
   *
   *
   */
  public List<String> getEid() {
    if (eid == null) {
      eid = new ArrayList<String>();
    }
    return this.eid;
  }

}

EmployeeInfo:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.06.23 at 04:28:35 PM CST 
//
package com.memorylack.www.ws.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for EmployeeInfo complex type.
 *
 * <p>The following schema fragment specifies the expected content contained within this class.
 *
 * <pre>
 * &lt;complexType name="EmployeeInfo">
 * &lt;complexContent>
 * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 * &lt;sequence>
 * &lt;element name="eid" type="{http://www.memorylack.com/company}EmployeeId" minOccurs="0"/>
 * &lt;element name="firstName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 * &lt;element name="lastName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 * &lt;element name="age" type="{http://www.w3.org/2001/XMLSchema}unsignedShort" minOccurs="0"/>
 * &lt;element name="title" type="{http://www.memorylack.com/company}EmployeeTitle" minOccurs="0"/>
 * &lt;/sequence>
 * &lt;/restriction>
 * &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EmployeeInfo", propOrder = {
    "eid",
    "firstName",
    "lastName",
    "age",
    "title"
})
public class EmployeeInfo {

  protected String eid;
  protected String firstName;
  protected String lastName;
  @XmlSchemaType(name = "unsignedShort")
  protected Integer age;
  protected EmployeeTitle title;

  /**
   * Gets the value of the eid property.
   *
   * @return
   * possible object is
   * {@link String }
   *
   */
  public String getEid() {
    return eid;
  }

  /**
   * Sets the value of the eid property.
   *
   * @param value
   * allowed object is
   * {@link String }
   *
   */
  public void setEid(String value) {
    this.eid = value;
  }

  /**
   * Gets the value of the firstName property.
   *
   * @return
   * possible object is
   * {@link String }
   *
   */
  public String getFirstName() {
    return firstName;
  }

  /**
   * Sets the value of the firstName property.
   *
   * @param value
   * allowed object is
   * {@link String }
   *
   */
  public void setFirstName(String value) {
    this.firstName = value;
  }

  /**
   * Gets the value of the lastName property.
   *
   * @return
   * possible object is
   * {@link String }
   *
   */
  public String getLastName() {
    return lastName;
  }

  /**
   * Sets the value of the lastName property.
   *
   * @param value
   * allowed object is
   * {@link String }
   *
   */
  public void setLastName(String value) {
    this.lastName = value;
  }

  /**
   * Gets the value of the age property.
   *
   * @return
   * possible object is
   * {@link Integer }
   *
   */
  public Integer getAge() {
    return age;
  }

  /**
   * Sets the value of the age property.
   *
   * @param value
   * allowed object is
   * {@link Integer }
   *
   */
  public void setAge(Integer value) {
    this.age = value;
  }

  /**
   * Gets the value of the title property.
   *
   * @return
   * possible object is
   * {@link EmployeeTitle }
   *
   */
  public EmployeeTitle getTitle() {
    return title;
  }

  /**
   * Sets the value of the title property.
   *
   * @param value
   * allowed object is
   * {@link EmployeeTitle }
   *
   */
  public void setTitle(EmployeeTitle value) {
    this.title = value;
  }

}

EmployeeInfoWrapper:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.06.23 at 04:28:35 PM CST 
//
package com.memorylack.www.ws.model;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for EmployeeInfoWrapper complex type.
 *
 * <p>The following schema fragment specifies the expected content contained within this class.
 *
 * <pre>
 * &lt;complexType name="EmployeeInfoWrapper">
 * &lt;complexContent>
 * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 * &lt;sequence>
 * &lt;element name="employeeInfo" type="{http://www.memorylack.com/company}EmployeeInfo" maxOccurs="unbounded" minOccurs="0"/>
 * &lt;/sequence>
 * &lt;/restriction>
 * &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EmployeeInfoWrapper", propOrder = {
    "employeeInfo"
})
public class EmployeeInfoWrapper {

  protected List<EmployeeInfo> employeeInfo;

  /**
   * Gets the value of the employeeInfo property.
   *
   * <p>
   * This accessor method returns a reference to the live list,
   * not a snapshot. Therefore any modification you make to the
   * returned list will be present inside the JAXB object.
   * This is why there is not a <CODE>set</CODE> method for the employeeInfo property.
   *
   * <p>
   * For example, to add a new item, do as follows:
   * <pre>
   * getEmployeeInfo().add(newItem);
   * </pre>
   *
   *
   * <p>
   * Objects of the following type(s) are allowed in the list
   * {@link EmployeeInfo }
   *
   *
   */
  public List<EmployeeInfo> getEmployeeInfo() {
    if (employeeInfo == null) {
      employeeInfo = new ArrayList<EmployeeInfo>();
    }
    return this.employeeInfo;
  }

}

EmployeeTitle:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.06.23 at 04:28:35 PM CST 
//
package com.memorylack.www.ws.model;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for EmployeeTitle.
 *
 * <p>The following schema fragment specifies the expected content contained within this class.
 * <p>
 * <pre>
 * &lt;simpleType name="EmployeeTitle">
 * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
 * &lt;enumeration value="CEO"/>
 * &lt;enumeration value="Manger"/>
 * &lt;enumeration value="Supervisor"/>
 * &lt;enumeration value="Clerk"/>
 * &lt;/restriction>
 * &lt;/simpleType>
 * </pre>
 *
 */
@XmlType(name = "EmployeeTitle")
@XmlEnum
public enum EmployeeTitle {

  CEO("CEO"),
  @XmlEnumValue("Manger")
  MANGER("Manger"),
  @XmlEnumValue("Supervisor")
  SUPERVISOR("Supervisor"),
  @XmlEnumValue("Clerk")
  CLERK("Clerk");
  private final String value;

  EmployeeTitle(String v) {
    value = v;
  }

  public String value() {
    return value;
  }

  public static EmployeeTitle fromValue(String v) {
    for (EmployeeTitle c: EmployeeTitle.values()) {
      if (c.value.equals(v)) {
        return c;
      }
    }
    throw new IllegalArgumentException(v);
  }

}

ObjectFactory:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.06.23 at 04:28:35 PM CST 
//
package com.memorylack.www.ws.model;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

/**
 * This object contains factory methods for each
 * Java content interface and Java element interface
 * generated in the com.memorylack.www.ws.model package.
 * <p>An ObjectFactory allows you to programatically
 * construct new instances of the Java representation
 * for XML content. The Java representation of XML
 * content can consist of schema derived interfaces
 * and classes representing the binding of schema
 * type definitions, element declarations and model
 * groups. Factory methods for each of these are
 * provided in this class.
 *
 */
@XmlRegistry
public class ObjectFactory {

  private final static QName _EmployeeIdList_QNAME = new QName("http://www.memorylack.com/company", "EmployeeIdList");
  private final static QName _EmployeeInfoList_QNAME = new QName("http://www.memorylack.com/company", "EmployeeInfoList");

  /**
   * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.memorylack.www.ws.model
   *
   */
  public ObjectFactory() {
  }

  /**
   * Create an instance of {@link EmployeeIdWrapper }
   *
   */
  public EmployeeIdWrapper createEmployeeIdWrapper() {
    return new EmployeeIdWrapper();
  }

  /**
   * Create an instance of {@link EmployeeInfoWrapper }
   *
   */
  public EmployeeInfoWrapper createEmployeeInfoWrapper() {
    return new EmployeeInfoWrapper();
  }

  /**
   * Create an instance of {@link EmployeeInfo }
   *
   */
  public EmployeeInfo createEmployeeInfo() {
    return new EmployeeInfo();
  }

  /**
   * Create an instance of {@link JAXBElement }{@code <}{@link EmployeeIdWrapper }{@code >}}
   *
   */
  @XmlElementDecl(namespace = "http://www.memorylack.com/company", name = "EmployeeIdList")
  public JAXBElement<EmployeeIdWrapper> createEmployeeIdList(EmployeeIdWrapper value) {
    return new JAXBElement<EmployeeIdWrapper>(_EmployeeIdList_QNAME, EmployeeIdWrapper.class, null, value);
  }

  /**
   * Create an instance of {@link JAXBElement }{@code <}{@link EmployeeInfoWrapper }{@code >}}
   *
   */
  @XmlElementDecl(namespace = "http://www.memorylack.com/company", name = "EmployeeInfoList")
  public JAXBElement<EmployeeInfoWrapper> createEmployeeInfoList(EmployeeInfoWrapper value) {
    return new JAXBElement<EmployeeInfoWrapper>(_EmployeeInfoList_QNAME, EmployeeInfoWrapper.class, null, value);
  }

}

package-info:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.06.23 at 04:28:35 PM CST 
//
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.memorylack.com/company", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.memorylack.www.ws.model;

Please copy .java file yo your WAR project and create a class named EmployeeLookupService:

package com.ctlok.pro.ws;
import java.util.HashMap;
import java.util.Map;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;

import com.memorylack.www.ws.model.EmployeeIdWrapper;
import com.memorylack.www.ws.model.EmployeeInfo;
import com.memorylack.www.ws.model.EmployeeInfoWrapper;
import com.memorylack.www.ws.model.EmployeeTitle;
import com.memorylack.www.ws.model.ObjectFactory;

@WebService(
    name = "employeeLookupService",
    serviceName = "employeeLookupService",
    portName = "employeeLookupPort",
    targetNamespace= "http://www.memorylack.com/company",
    wsdlLocation = "company.wsdl")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({ObjectFactory.class})
public class EmployeeLookupService {

  private Map<String, EmployeeInfo> infoMap;

  public EmployeeLookupService(){
    infoMap = new HashMap<String, EmployeeInfo>();

    EmployeeInfo info1 = new EmployeeInfo();
    info1.setEid("E1000000");
    info1.setFirstName("Lawrence");
    info1.setLastName("Cheung");
    info1.setAge(24);
    info1.setTitle(EmployeeTitle.CEO);

    EmployeeInfo info2 = new EmployeeInfo();
    info2.setEid("E1524125");
    info2.setFirstName("Tom");
    info2.setLastName("Wong");
    info2.setAge(22);
    info2.setTitle(EmployeeTitle.CLERK);

    EmployeeInfo info3 = new EmployeeInfo();
    info3.setEid("E7452145");
    info3.setFirstName("John");
    info3.setLastName("Lee");
    info3.setAge(29);
    info3.setTitle(EmployeeTitle.MANGER);

    EmployeeInfo info4 = new EmployeeInfo();
    info4.setEid("E6523547");
    info4.setFirstName("Katty");
    info4.setLastName("Choi");
    info4.setAge(24);
    info4.setTitle(EmployeeTitle.SUPERVISOR);

    infoMap.put(info1.getEid(), info1);
    infoMap.put(info2.getEid(), info2);
    infoMap.put(info3.getEid(), info3);
    infoMap.put(info4.getEid(), info4);
  }

  @WebMethod(operationName="employeeLookup")
  @WebResult(name = "EmployeeInfoList", partName = "employeeInfoList")
  public EmployeeInfoWrapper employeeLookup(
      @WebParam(name = "EmployeeIdList", partName = "employeeIdList")
          EmployeeIdWrapper employeeIdWrapper){

    EmployeeInfoWrapper employeeInfoWrapper = new EmployeeInfoWrapper();

    for (String eid: employeeIdWrapper.getEid()){
      EmployeeInfo info = infoMap.get(eid);

      if (info == null)
        info = new EmployeeInfo();

      employeeInfoWrapper.getEmployeeInfo().add(info);
    }

    return employeeInfoWrapper;

  }

}

Now, you have complete the web service provider.
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)

This annotation default value is WRAPPED. JAX-WS auto create a wrapper to wrap the object. In company.xsd, I have a wrapper so do not need this option. Set value to BARE to avoid JAX-WS auto create a wrapper.

——————- separate ——————-

@XmlSeeAlso({ObjectFactory.class})

This annotation will be allowed on any JAXB-bound type, and when JAXB binds that type, classes listed in @XmlSeeAlso will be also bound.

——————- separate ——————-

@WebResult(
    name = "EmployeeInfoList", 
    partName = "employeeInfoList")

This annotation is mapped with WSDL:

<wsdl:message name="employeeLookupRequest">
    <wsdl:part element="tns:EmployeeIdList" name="employeeIdList" />
</wsdl:message>

——————- separate ——————-

@WebResult(
    name = "EmployeeInfoList", 
    partName = "employeeInfoList")

This annotation is mapped with WSDL:

<wsdl:message name="employeeLookupResponse">
    <wsdl:part element="tns:EmployeeInfoList" name="employeeInfoList" />
</wsdl:message>

Now you can deploy this project to application server and run this URL in browser: http://localhost/employeeLookupService?wsdl.

If this URL not equal your project URL, please modify WSDL address:

<wsdl:service name="employeeLookupService">
    <wsdl:port binding="tns:employeeLookupBinding" name="employeeLookupPort">
        <soap:address location="http://localhost" />
    </wsdl:port>
</wsdl:service>

Complete this part you can use soapUI to test your Web Service Provider. soapUI sent below SOAP XML to server:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:com="http://www.memorylack.com/company">
   <soapenv:Header/>
   <soapenv:Body>
      <com:EmployeeIdList>
         <!--Zero or more repetitions:-->
         <com:eid>E1000000</com:eid>
         <com:eid>E1524125</com:eid>
      </com:EmployeeIdList>
   </soapenv:Body>
</soapenv:Envelope>

Server response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <EmployeeInfoList xmlns="http://www.memorylack.com/company">
         <employeeInfo>
            <eid>E1000000</eid>
            <firstName>Lawrence</firstName>
            <lastName>Cheung</lastName>
            <age>24</age>
            <title>CEO</title>
         </employeeInfo>
         <employeeInfo>
            <eid>E1524125</eid>
            <firstName>Tom</firstName>
            <lastName>Wong</lastName>
            <age>22</age>
            <title>Clerk</title>
         </employeeInfo>
      </EmployeeInfoList>
   </soapenv:Body>
</soapenv:Envelope>