1 SOAP client example
A SOAP request can be formulated by generating an XML message that will be transported using the HTTP protocol. The preparation of the XML message (serialization) and obtaining the response (deserialization) can be done through different languages.
Below are some examples in the most common languages.
1.1 XSQL-Script client
This section shows several examples of SOAP clients using the XSQL-SCRIPTS language.
1.1.1 SOAPXMLServer.executeXML
Example 1
Invoke a XSQL-SCRIPT.
<xsql-script name='callXSQLScript'> <body> <set name='m_response'> <soap.call url='http://www.mydeister.com/soap/servlet/rpcrouter' uri='urn:SOAPXMLServer' method='executeXML' user='soap' password='soap999' > <parameters> <parameter name='database'>demo_formacion</parameter> <parameter name='xml_code'><call name = "test_script"><args><arg>TEST CALL SCRIPT</arg></args></call></parameter> </parameters> </soap.call> </set> <println><m_response/></println> </body> </xsql-script>
Example 2
Invoke XSQL-SCRIPT with argument array.
<xsql-script name='callXSQLScript'> <body> <array name = 'm_arg_data'> <string>0000000171083</string> </array> <set name='m_response'> <soap.call url='http://www.mydeister.com/soap/servlet/rpcrouter' uri='urn:SOAPXMLServer' method='executeXML' user='soap' password='soap999' > <parameters> <parameter name='database'>demo_formacion</parameter> <parameter name='xml_code'>LeerStock</parameter> <parameter name='arg_data'><m_arg_data/></parameter> </parameters> </soap.call> </set> <println><m_response/></println> </body> </xsql-script>
1.2 Java Client (Apache SOAP 2.3)
In this section we will show several examples of java clients developed using APACHE SOAP libraries.
1.2.1 Previous requirements
To compile or execute the examples detailed in this section, at least the libraries detailed below are required and can be found at common/lib/ webstudio:
- common/lib/webstudio/soap.jar (Apache Soap 2.3)
- common/lib/webstudio/activation.jar (JavaBeans Activation Framework.)
- common/lib/webstudio/mail/jmail_1_4_mail.jar (Java Mail 1.4)
1.2.2 Compilation
An example of compiling a java client could be the following, where SOAPOBJClient1.java is the java code file:
javac -classpath soap.jar SOAPOBJClient1.java
1.2.3 Execution
An example of executing a java client could be the following, where SOAPOBJClient1 is the java class file, to which two arguments are passed:
java -classpath soap.jar;jmail_1_4_mail.jar;activation.jar;. SOAPOBJClient1 http://192.10.10.1/soap/servlet/rpcrouter demo_sports1
1.2.4 SOAPXMLServer.executeXML
Example 1
This example shows how to execute an XSQL-SCRIPT process to which an XML document is passed as an argument. It is about generating a sales order from an XML file with a default format. In our case, an example of the XML file could be the following:
<pedido> <cabecera> <tipo>PVDS</tipo> <empresa>IASA</empresa> <delegacion>01</delegacion> <departamento>0</departamento> <fecha>13-05-2013</fecha> <cliente>0</cliente> </cabecera> <lineas> <linea> <articulo>000001</articulo> <cantidad>20</cantidad> </linea> <linea> <articulo>000002</articulo> <cantidad>10</cantidad> </linea> </lineas> </pedido>
The XSQL-SCRIPT process that generates the sales order would be like the following example:
<xsql-script name='pedido_load'> <args> <arg name='p_xmlarg' type='string'/> </args> <body> <function name ='local_get_value'> <args> <arg name='p_root'/> <arg name='p_path' type='string'/> </args> <body> <return> <dom.node.getNodeValue> <dom.node.getFirstChild> <dom.getElementByXPath xpath='#p_path'> <p_root/> </dom.getElementByXPath> </dom.node.getFirstChild> </dom.node.getNodeValue> </return> </body> </function> <set name = 'm_root'> <dom.parse><p_xmlarg/></dom.parse> </set> <set name = 'new_tipdoc'> <local_get_value> <m_root/> <string>/pedido/cabecera/tipo</string> </local_get_value> </set> <set name = 'new_empcode'> <local_get_value> <m_root/> <string>/pedido/cabecera/empresa</string> </local_get_value> </set> <set name = 'new_delega'> <local_get_value> <m_root/> <string>/pedido/cabecera/delegacion</string> </local_get_value> </set> <set name = 'new_depart'> <local_get_value> <m_root/> <string>/pedido/cabecera/departamento</string> </local_get_value> </set> <set name = 'new_fecha'> <date.parse format='dd-MM-yyyy'> <local_get_value> <m_root/> <string>/pedido/cabecera/fecha</string> </local_get_value> </date.parse> </set> <set name = 'new_tercer'> <local_get_value> <m_root/> <string>/pedido/cabecera/cliente</string> </local_get_value> </set> <call name='gvenpedh_init' into='v_gvenpedh'/> <vtable.insert name='v_gvenpedh' prefix='new_'/> <call name='gvenpedh_insert' into='m_cabid'> <string>INSERT</string> <v_gvenpedh/> </call> <select prefix='gvenpedh_'> <columns> rowid, docser, fecini, fecfin </columns> <from table='gvenpedh'/> <where> gvenpedh.cabid = <m_cabid/> </where> </select> <set name='m_lineas'> <dom.getElementByXPath xpath='/pedido/lineas'> <m_root/> </dom.getElementByXPath> </set> <if><expr><isnotnull><m_lineas/></isnotnull></expr> <then> <set name='m_linea'> <dom.element.getFirstChildElement><m_lineas /></dom.element.getFirstChildElement> </set> <set name ='gvenpedl_cabid'><m_cabid/></set> <set name ='gvenpedl_orden'>1</set> <set name ='gvenpedl_entini'><gvenpedh_fecini/></set> <set name ='gvenpedl_entfin'><gvenpedh_fecfin/></set> <set name ='gvenpedl_varlog'>0</set> <set name ='gvenpedl_udmven'>UNI</set> <set name ='gvenpedl_precio'>0</set> <set name ='gvenpedl_dtolin'>0</set> <set name ='gvenpedl_numlot'>0</set> <set name ='gvenpedl_canser'>0</set> <set name ='gvenpedl_canext'>0</set> <set name ='gvenpedl_canadj'>0</set> <set name ='gvenpedl_estlin'>E</set> <set name ='gvenpedl_errlin'>0</set> <set name ='gvenpedl_entpar'>0</set> <set name ='gvenpedl_adjpar'>0</set> <set name ='gvenpedl_pedcom'>0</set> <set name ='gvenpedl_impnet'>0</set> <while> <expr><isnotnull><m_linea/></isnotnull></expr> <do> <set name = 'm_node'> <dom.parse><m_linea/></dom.parse> </set> <set name ='gvenpedl_codart'> <local_get_value> <m_node/> <string>/linea/articulo</string> </local_get_value> </set> <set name ='gvenpedl_canped'> <local_get_value> <m_node/> <string>/linea/cantidad</string> </local_get_value> </set> <insert table = 'gvenpedl' prefix = 'gvenpedl_'/> <set name ='gvenpedl_orden'><add><gvenpedl_orden/>1</add></set> <set name='m_linea'> <dom.element.getNextSiblingElement><m_linea /></dom.element.getNextSiblingElement> </set> </do> </while> </then> </if> <call name='gvenpedh'> <string>V</string> <gvenpedh_rowid/> </call> <return><gvenpedh_docser/></return> </body> </xsql-script>
The java code for the SOAP client would be like the following example:
// java import java.net.URL; import java.util.Vector; import java.io.File; import java.io.FileInputStream; import java.io.ByteArrayOutputStream; // dom import org.w3c.dom.*; // apache SOAP import org.apache.soap.util.xml.DOM2Writer; import org.apache.soap.Fault; import org.apache.soap.Constants; import org.apache.soap.SOAPException; import org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; import org.apache.soap.transport.http.SOAPHTTPConnection; /** * org.w3c.dom.Element executeXML(String database, String xml_code, Vector<Object> arg_data) */ public class SOAPSCRIPTClient { public static void main(String[] args) throws Exception { if (args.length < 5) { System.err.println("Usage:"); System.err.println(" java " + SOAPSCRIPTClient.class.getName() + " url user pass database scriptcode xml_file" ); System.exit (1); } // Tomamos los argumentos de la linea de comandos. URL url = new URL(args[0]); String user = args[1]; String password = args[2]; String database = args[3]; String scriptcode = "<call name = '" + args[4] + "'/>"; String xml = getXmlCodeFromFile(args[5]); Vector arg_data = new Vector(); arg_data.addElement((Object) xml); //Build the object Call call = new Call(); // Autentificacion SOAPHTTPConnection hc = new SOAPHTTPConnection(); hc.setUserName(user); // USUARIO hc.setPassword(password); // PASSWORD call.setSOAPTransport(hc); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); call.setTargetObjectURI("urn:SOAPXMLServer"); call.setMethodName("executeXML"); // We pass 3 parameters to the direct execution function: // org.w3c.dom.Element executeXML(String database, String xml_code, Vector<Object> arg_data) Vector params = new Vector(); params.addElement( new Parameter( "database", String.class, database, Constants.NS_URI_SOAP_ENC ) ); params.addElement( new Parameter( "xml_code", String.class, scriptcode, Constants.NS_URI_SOAP_ENC ) ); params.addElement( new Parameter( "arg_data", Vector.class, arg_data, Constants.NS_URI_SOAP_ENC ) ); call.setParams(params); // Invocamos la llamada Response resp; try { resp = call.invoke(url, ""); } catch (SOAPException ex) { System.err.println("Caught SOAPException (" + ex.getFaultCode() + "): " + ex.getMessage() ); ex.printStackTrace(); return; } // We verify the answer and show it if (!resp.generatedFault()) { Parameter ret = resp.getReturnValue(); Element element = (Element)ret.getValue(); System.out.println(DOM2Writer.nodeToString(element)); } else { Fault fault = resp.getFault(); System.err.println("Fault code :" + fault.getFaultCode()); System.err.println("Fault string :" + fault.getFaultString()); System.err.println("Fault ActorURI:" + fault.getFaultActorURI()); Vector details = fault.getDetailEntries(); if (details != null) { while (details.size() > 0) { Object data = details.remove(0); System.err.println("Detail Entry :" + data.getClass().getName()); System.err.println(data); } } Vector entries = fault.getFaultEntries(); if (entries != null) { while (entries.size() > 0) { Object data = entries.remove(0); System.err.println("Fault Entry :" + data.getClass().getName()); System.err.println(data); } } } // if (!resp.generatedFault()) } // main /* * Receive a string with a filename where the xml is stored * Returns a String */ private static String getXmlCodeFromFile (String p_filename) throws Exception { //Leer fichero java.io.File file_data =null; try{ file_data = new java.io.File(p_filename); }catch (Exception ex){ System.err.println(ex); System.exit(1); } if (!file_data.exists()) { System.err.println(p_filename + " No existe."); System.exit(1); } java.io.FileInputStream data_stream = new FileInputStream(file_data); Long l_size = new Long(file_data.length()); int size = l_size.intValue(); byte[] data_byte = new byte[size]; data_stream.read(data_byte); java.io.ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(data_byte,0,size); String xmldata = out.toString(); return xmldata; } } // SOAPSCRIPTClient
Example 2
This example shows how to develop a soap client to perform XML transactions on the database. The program supports the following arguments:
- URL: the soap service url.
- USER: connection User.
- PASS: connection password.
- DBMS: the database on which the transaction is made.
- XML_FILE: full path of the file where the XML transaction to be executed is stored.
- proxyHost: proxy server, optional.
- proxyPort: proxy server port, optional.
- proxyUser: proxy server user, optionall.
- proxyPassword: proxy server password, optional.
Source code
// java import java.net.URL; import java.io.FileInputStream; import java.io.ByteArrayOutputStream; import java.util.Vector; // dom import org.w3c.dom.Element; // apache SOAP import org.apache.soap.Fault; import org.apache.soap.rpc.Call; import org.apache.soap.transport.http.SOAPHTTPConnection; import org.apache.soap.Constants; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; import org.apache.soap.SOAPException; import org.apache.soap.util.xml.DOM2Writer; /** * Example of a java client using apache soap to * invoke the executeXML operation of the SOPAXMLServer service * Element executeXML(String database, String xml_code) */ public class SOAPXMLClient { public static void main(String[] args) throws Exception { if (args.length != 5 && args.length != 7 && args.length != 9) { System.err.println("Usage:"); System.err.println(" java " + SOAPXMLClient.class.getName() + " url user pass database xml_code [proxyHost proxyPort] [proxyUser proxyPassword]" ); System.exit (1); } // We take the command line arguments URL url = new URL(args[0]); String user = args[1]; String password = args[2]; String database = args[3]; String xml_code = getXmlCodeFromFile(args[4]); //Build the object Call call = new Call(); // Authentication SOAPHTTPConnection hc = new SOAPHTTPConnection(); hc.setUserName(user); // USUARIO hc.setPassword(password); // PASSWORD // Observe si usa un proxy! if (args.length >= 7) { hc.setProxyHost(args[5]); //PROXY HOSTNAME hc.setProxyPort(Integer.parseInt(args[6])); //PROXY PORT if (args.length == 9) { hc.setProxyUserName(args[7]); //PROXY USER hc.setProxyPassword(args[8]); //PROXY PASSWORD } } call.setSOAPTransport(hc); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); call.setTargetObjectURI("urn:SOAPXMLServer"); call.setMethodName("executeXML"); // We pass 2 parameters to the direct execution function: // org.w3c.dom.Element executeXML(String database, String xml_code) Vector params = new Vector(); params.addElement( new Parameter( "database", String.class, database, Constants.NS_URI_SOAP_ENC ) ); params.addElement( new Parameter( "xml_code", String.class, xml_code, Constants.NS_URI_SOAP_ENC ) ); call.setParams(params); // We invoke the call Response resp; try { resp = call.invoke(url, ""); } catch (SOAPException ex) { System.err.println("Caught SOAPException (" + ex.getFaultCode() + "): " + ex.getMessage() ); ex.printStackTrace(); return; } // We verify the response and show it if (!resp.generatedFault()) { Parameter ret = resp.getReturnValue(); Element element = (Element)ret.getValue(); System.out.println(DOM2Writer.nodeToString(element)); } else { Fault fault = resp.getFault(); System.err.println("Fault code :" + fault.getFaultCode()); System.err.println("Fault string :" + fault.getFaultString()); System.err.println("Fault ActorURI:" + fault.getFaultActorURI()); Vector details = fault.getDetailEntries(); if (details != null) { while (details.size() > 0) { Object data = details.remove(0); System.err.println("Detail Entry :" + data.getClass().getName()); System.err.println(data); } } Vector entries = fault.getFaultEntries(); if (entries != null) { while (entries.size() > 0) { Object data = entries.remove(0); System.err.println("Fault Entry :" + data.getClass().getName()); System.err.println(data); } } } // if (!resp.generatedFault()) } /* * Receive a string with file name where the XML transaction to be executed is stored * Returns a String */ private static String getXmlCodeFromFile (String p_filename) throws Exception { //Read file java.io.File file_data =null; try{ file_data = new java.io.File(p_filename); }catch (Exception ex){ System.err.println(ex); System.exit(1); } if (!file_data.exists()) { System.err.println(p_filename + " No existe."); System.exit(1); } java.io.FileInputStream data_stream = new FileInputStream(file_data); Long l_size = new Long(file_data.length()); int size = l_size.intValue(); byte[] data_byte = new byte[size]; data_stream.read(data_byte); java.io.ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(data_byte,0,size); String xmldata = out.toString(); return xmldata; } }
Insert a record on a table
<sqltransaction> <insert table='ctipoter'> <row> <codigo>TST</codigo> <nomter>TEST</nomter> <serter></serter> <cusrel></cusrel> <cuscta></cuscta> <cusret>0</cusret> <suprel>P</suprel> <supcta></supcta> <supret>0</supret> <copacc>0</copacc> <cartype></cartype> <tipwkf></tipwkf> </row> </insert> </sqltransaction>
Sample response on a successful XML transaction
<sqlresponse date="2014-07-25T15:44:04.793Z" host="customer2"> <sqlinfo commits="1" deletes="0" inserts="1" rollbacks="0" updates="0"> <xmlmd5>cf6df39bd4eb3e5e317fdf467e1cff28</xmlmd5> <sqluser>deister_ajz</sqluser> <sqldbms>demo</sqldbms> <autoincrement> <atomic id="0"> <insert column="" ref="" serial="0" table="ctipoter"/> </atomic> </autoincrement> </sqlinfo> </sqlresponse>
Sample response on an XML transaction with error
<sqlresponse date="2014-07-25T15:45:43.978Z" host="customer2"> <sqlinfo commits="0" deletes="0" inserts="0" rollbacks="1" updates="0"> <xmlmd5>cf6df39bd4eb3e5e317fdf467e1cff28</xmlmd5> <sqluser>deister_ajz</sqluser> <sqldbms>demo</sqldbms> <rollbacks> <atomic id="0" ref=""> <exception> <errmessg class="java.sql.SQLException" sqlcode="-268" sqlstate="23000"> <![CDATA[java.sql.SQLException: Unique constraint (informix.p_ctipoter) violated .]]> </errmessg> <errtrace> <![CDATA[ > FROM [0] java.sql.SQLException java.sql.SQLException: Unique constraint (informix.p_ctipoter) violated. at com.informix.jdbc.IfxSqli.a(IfxSqli.java:3609) at com.informix.jdbc.IfxSqli.E(IfxSqli.java:3934) at com.informix.jdbc.IfxSqli.dispatchMsg(IfxSqli.java:2682) at com.informix.jdbc.IfxSqli.receiveMessage(IfxSqli.java:2598) at com.informix.jdbc.IfxSqli.executeCommand(IfxSqli.java:939) at com.informix.jdbc.IfxResultSet.b(IfxResultSet.java:303) at com.informix.jdbc.IfxStatement.c(IfxStatement.java:1276) at com.informix.jdbc.IfxPreparedStatement.executeUpdate(IfxPreparedState ment.java:421) at deister.webstudio.core.dbms.jdbc.DBPoolPreparedStatement.executeUpdat e(DBPoolPreparedStatement.java:308) at deister.webstudio.core.dbms.jdbc.DBPoolConnection.executeUpdate(DBPoo lConnection.java:3424) at deister.webstudio.core.dbms.jdbc.DBPoolConnection.executeUpdate(DBPoo lConnection.java:3370) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.a(XMLS QLTransactionDigester.java:436) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.a(XMLS QLTransactionDigester.java:366) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.a(XMLS QLTransactionDigester.java:355) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.a(XMLS QLTransactionDigester.java:302) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.digest (XMLSQLTransactionDigester.java:159) at deister.webstudio.core.services.soap.SOAPXMLServer.__execute_XML_XTRA (SOAPXMLServer.java:327) at deister.webstudio.core.services.soap.SOAPXMLServer.executeXML(SOAPXML Server.java:204) at deister.webstudio.core.services.soap.SOAPXMLServer.executeXML(SOAPXML Server.java:189) at deister.webstudio.core.services.soap.SOAPXMLServer.executeXML(SOAPXML Server.java:184) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl. java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces sorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.soap.server.RPCRouter.invoke(Unknown Source) at deister.webstudio.core.services.soap.SimpleAuthenticationJavaProvider .invoke(SimpleAuthenticationJavaProvider.java:564) at org.apache.soap.server.http.RPCRouterServlet.doPost(RPCRouterServlet. java:393) at javax.servlet.http.HttpServlet.service(HttpServlet.java:647) at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl icationFilterChain.java:269) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF ilterChain.java:188) at deister.webstudio.core.server.filters.ExpiresFilter.doFilter(ExpiresF ilter.java:1266) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl icationFilterChain.java:215) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF ilterChain.java:188) at deister.webstudio.core.server.filters.CharsetRequestFilter.doFilter(C harsetRequestFilter.java:149) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl icationFilterChain.java:215) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF ilterChain.java:188) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperV alve.java:213) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextV alve.java:172) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(Authentica torBase.java:470) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.j ava:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.j ava:117) at deister.webstudio.login.valves.TokenProcessValve.invoke(TokenProcessV alve.java:181) at deister.webstudio.login.valves.TokenLoginValve.invoke(TokenLoginValve .java:181) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java: 581) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineVal ve.java:108) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.jav a:174) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java :879) at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.p rocessConnection(Http11BaseProtocol.java:665) at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpo int.java:528) at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFol lowerWorkerThread.java:81) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadP ool.java:689) at java.lang.Thread.run(Thread.java:662) Caused by: java.sql.SQLException: ISAM error: duplicate value for a record with unique key. at com.informix.util.IfxErrMsg.getSQLException(IfxErrMsg.java:413) at com.informix.jdbc.IfxSqli.E(IfxSqli.java:3939) ... 51 more SQL ERROR: -268 Violación de restricción única (%s). SQL STATE: 23000 > FROM [1] java.sql.SQLException java.sql.SQLException: ISAM error: duplicate value for a record with unique key. at com.informix.util.IfxErrMsg.getSQLException(IfxErrMsg.java:413) at com.informix.jdbc.IfxSqli.a(IfxSqli.java:3613) at com.informix.jdbc.IfxSqli.E(IfxSqli.java:3938) at com.informix.jdbc.IfxSqli.dispatchMsg(IfxSqli.java:2682) at com.informix.jdbc.IfxSqli.receiveMessage(IfxSqli.java:2598) at com.informix.jdbc.IfxSqli.executeCommand(IfxSqli.java:939) at com.informix.jdbc.IfxResultSet.b(IfxResultSet.java:303) at com.informix.jdbc.IfxStatement.c(IfxStatement.java:1276) at com.informix.jdbc.IfxPreparedStatement.executeUpdate(IfxPreparedState ment.java:421) at deister.webstudio.core.dbms.jdbc.DBPoolPreparedStatement.executeUpdat e(DBPoolPreparedStatement.java:308) at deister.webstudio.core.dbms.jdbc.DBPoolConnection.executeUpdate(DBPoo lConnection.java:3424) at deister.webstudio.core.dbms.jdbc.DBPoolConnection.executeUpdate(DBPoo lConnection.java:3370) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.a(XMLS QLTransactionDigester.java:436) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.a(XMLS QLTransactionDigester.java:366) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.a(XMLS QLTransactionDigester.java:355) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.a(XMLS QLTransactionDigester.java:302) at deister.webstudio.core.services.soap.XMLSQLTransactionDigester.digest (XMLSQLTransactionDigester.java:159) at deister.webstudio.core.services.soap.SOAPXMLServer.__execute_XML_XTRA (SOAPXMLServer.java:327) at deister.webstudio.core.services.soap.SOAPXMLServer.executeXML(SOAPXML Server.java:204) at deister.webstudio.core.services.soap.SOAPXMLServer.executeXML(SOAPXML Server.java:189) at deister.webstudio.core.services.soap.SOAPXMLServer.executeXML(SOAPXML Server.java:184) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl. java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces sorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.soap.server.RPCRouter.invoke(Unknown Source) at deister.webstudio.core.services.soap.SimpleAuthenticationJavaProvider .invoke(SimpleAuthenticationJavaProvider.java:564) at org.apache.soap.server.http.RPCRouterServlet.doPost(RPCRouterServlet. java:393) at javax.servlet.http.HttpServlet.service(HttpServlet.java:647) at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl icationFilterChain.java:269) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF ilterChain.java:188) at deister.webstudio.core.server.filters.ExpiresFilter.doFilter(ExpiresF ilter.java:1266) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl icationFilterChain.java:215) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF ilterChain.java:188) at deister.webstudio.core.server.filters.CharsetRequestFilter.doFilter(C harsetRequestFilter.java:149) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl icationFilterChain.java:215) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF ilterChain.java:188) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperV alve.java:213) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextV alve.java:172) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(Authentica torBase.java:470) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.j ava:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.j ava:117) at deister.webstudio.login.valves.TokenProcessValve.invoke(TokenProcessV alve.java:181) at deister.webstudio.login.valves.TokenLoginValve.invoke(TokenLoginValve .java:181) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java: 581) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineVal ve.java:108) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.jav a:174) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java :879) at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.p rocessConnection(Http11BaseProtocol.java:665) at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpo int.java:528) at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFol lowerWorkerThread.java:81) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadP ool.java:689) at java.lang.Thread.run(Thread.java:662) SQL ERROR: -100 Error ISAM: valor duplicado para un registro de clave ún ica SQL STATE: IX000 > FROM [2] deister.webstudio.core.dbms.jdbc.SQLExceptionInfo SQLExceptionInfo: class=RW,server=primary,dbms=demo,group=deister {1} INSERT INTO ctipoter (codigo,nomter,serter,cusrel,cuscta,cusret,suprel,supcta,supret,copacc,cartype,t ipwkf) VALUES (?,?,?,?,?,?,?,?,?,?,?,?) > FROM [3] deister.webstudio.core.dbms.jdbc.SQLExceptionInfo SQLExceptionInfo: class=RW,server=primary,dbms=demo,group=deister {1} column 0 of type (1, CHAR) = TST, class=java.lang.String column 1 of type (1, CHAR) = TEST, class=java.lang.String column 2 of type (1, CHAR) = null, class=null column 3 of type (1, CHAR) = null, class=null column 4 of type (1, CHAR) = null, class=null column 5 of type (5, SMALLINT) = 0, class=java.lang.Short column 6 of type (1, CHAR) = P, class=java.lang.String column 7 of type (1, CHAR) = null, class=null column 8 of type (5, SMALLINT) = 0, class=java.lang.Short column 9 of type (5, SMALLINT) = 0, class=java.lang.Short column 10 of type (1, CHAR) = null, class=null column 11 of type (1, CHAR) = null, class=null ]]> </errtrace> </exception> </atomic> </rollbacks> </sqlinfo> </sqlresponse>
Ejemplo de insertar varios registros sobre la misma tabla
<sqltransaction> <insert table='ctipoter'> <row> <codigo>TST</codigo> <nomter>TEST</nomter> <serter></serter> <cusrel></cusrel> <cuscta></cuscta> <cusret>0</cusret> <suprel>P</suprel> <supcta></supcta> <supret>0</supret> <copacc>0</copacc> <cartype></cartype> <tipwkf></tipwkf> </row> <row> <codigo>TST1</codigo> <nomter>TEST</nomter> <serter></serter> <cusrel></cusrel> <cuscta></cuscta> <cusret>0</cusret> <suprel>P</suprel> <supcta></supcta> <supret>0</supret> <copacc>0</copacc> <cartype></cartype> <tipwkf></tipwkf> </row> </insert> </sqltransaction>
Note
In this example, all insert operations are performed in a single transaction, that is, if one of them fails, all of them are rollback.
Example of inserting multiple records with independent transactions
<sqltransaction> <atomic> <insert table='ctipoter'> <row> <codigo>TST</codigo> <nomter>TEST</nomter> <serter></serter> <cusrel></cusrel> <cuscta></cuscta> <cusret>0</cusret> <suprel>P</suprel> <supcta></supcta> <supret>0</supret> <copacc>0</copacc> <cartype></cartype> <tipwkf></tipwkf> </row> </insert> </atomic> <atomic> <insert table='ctipoter'> <row> <codigo>TST</codigo> <nomter>TEST</nomter> <serter></serter> <cusrel></cusrel> <cuscta></cuscta> <cusret>0</cusret> <suprel>P</suprel> <supcta></supcta> <supret>0</supret> <copacc>0</copacc> <cartype></cartype> <tipwkf></tipwkf> </row> </insert> </atomic> </sqltransaction>
Nota
In this example, all operations grouped within the same element atomic are performed with separate transactions.
Example of performing several xml operations with a reference attribute in order to identify each operation on the response xml
<sqltransaction> <atomic> <insert table='ctipoter' ref='TST1'> <row> <codigo>TST1</codigo> <nomter>TEST</nomter> <serter></serter> <cusrel></cusrel> <cuscta></cuscta> <cusret>0</cusret> <suprel>P</suprel> <supcta></supcta> <supret>0</supret> <copacc>0</copacc> <cartype></cartype> <tipwkf></tipwkf> </row> </insert> </atomic> <atomic> <insert table='ctipoter' ref ='TST2'> <row> <codigo>TST2</codigo> <nomter>TEST</nomter> <serter></serter> <cusrel></cusrel> <cuscta></cuscta> <cusret>0</cusret> <suprel>P</suprel> <supcta></supcta> <supret>0</supret> <copacc>0</copacc> <cartype></cartype> <tipwkf></tipwkf> </row> </insert> </atomic> </sqltransaction>
The answer in that case would be this way:
<sqlresponse date="2014-07-25T16:45:48.628Z" host="customer2"> <sqlinfo commits="2" deletes="0" inserts="2" rollbacks="0" updates="0"> <xmlmd5>90e6381484727d446ae31a783f161ac2</xmlmd5> <sqluser>deister_ajz</sqluser> <sqldbms>demo</sqldbms> <autoincrement> <atomic id="0"> <insert column="" ref="TST1" serial="0" table="ctipoter"/> </atomic> <atomic id="1"> <insert column="" ref="TST2" serial="0" table="ctipoter"/> </atomic> </autoincrement> </sqlinfo> </sqlresponse>
Example of performing nested xml transactions, header case and lines
<sqltransaction> <atomic> <insert table='gcompedh'> <row> <cabid/> <tipdoc>PCMU</tipdoc> <empcode>02</empcode> <delega>02</delega> <depart>50005</depart> <fecha dd='21' mm='7' yy='2014'>7/21/14</fecha> <docser>0214PCMU-</docser> <tercer>011882</tercer> <tipdir>0</tipdir> <divisa>EUR</divisa> <cambio>1.000000</cambio> <impres>N</impres> <estcab>V</estcab> <errcab>0</errcab> <wkfcab></wkfcab> <coment></coment> <tipefe>CF</tipefe> <frmpag>90</frmpag> <terenv>02</terenv> <direnv>0</direnv> <terfac>011882</terfac> <dirfac>0</dirfac> <codnac>ESP</codnac> <nomnac><![CDATA[España]]></nomnac> <codpos>03203</codpos> <codprv>03</codprv> <fecini dd='21' mm='7' yy='2014'>7/21/14</fecini> <fecfin dd='21' mm='7' yy='2014'>7/21/14</fecfin> <imptot>0.00</imptot> <impant>0.00</impant> <dtogen>0.000</dtogen> <dtopp>0.000</dtopp> <porgar>0.00</porgar> <portes>D</portes> <impaux></impaux> <movedi>0</movedi> <movest>0</movest> <movhis>0</movhis> <codalm>A09</codalm> <codcom></codcom> <indmod>S</indmod> <auxchr1>MU</auxchr1> <auxchr2>141</auxchr2> </row> <insert table='gcompedl'> <row> <linid/> <cabid>{gcompedh.cabid}</cabid> <orden>2</orden> <entini dd='21' mm='7' yy='2014'>7/21/14</entini> <entfin dd='21' mm='7' yy='2014'>7/21/14</entfin> <codart>V141005241501/MP</codart> <varlog>37</varlog> <desvar><![CDATA[52415]]></desvar> <numlot>0</numlot> <canped>12.000</canped> <canalt></canalt> <udmcom>C13733</udmcom> <udmalt></udmalt> <canpre>12.000</canpre> <udmpre>C13733</udmpre> <precio>0.000000</precio> <dtolin>0.0000</dtolin> <udmrec></udmrec> <pretar></pretar> <dtotar></dtotar> <canser>0.000</canser> <canfac>0.000</canfac> <canadj>0.000</canadj> <canext>0.000</canext> <impnet>0.00</impnet> <terexp></terexp> <direxp></direxp> <estlin>V</estlin> <errlin>0</errlin> <wkflin></wkflin> <desamp></desamp> <indmod>S</indmod> <regalo>N</regalo> <linori></linori> </row> </insert> <insert table='gcompedl'> <row> <linid/> <cabid>{gcompedh.cabid}</cabid> <orden>4</orden> <codart>V141005241501/MP</codart> <varlog>37</varlog> <desvar><![CDATA[52415]]></desvar> <numlot>0</numlot> <canped>12.000</canped> <canalt></canalt> <udmcom>C13732</udmcom> <udmalt></udmalt> <canpre>12.000</canpre> <udmpre>C13732</udmpre> <precio>0.000000</precio> <dtolin>0.0000</dtolin> <udmrec></udmrec> <pretar></pretar> <dtotar></dtotar> <canser>0.000</canser> <canfac>0.000</canfac> <canadj>0.000</canadj> <canext>0.000</canext> <impnet>0.00</impnet> <terexp></terexp> <direxp></direxp> <estlin>V</estlin> <errlin>0</errlin> <wkflin></wkflin> <desamp></desamp> <indmod>S</indmod> <regalo>N</regalo> </row> </insert> </insert> </atomic> </sqltransaction>
Note
This example shows that the {gcompedh.cabid} statement refers to the cabid column value of the parent table gcompedh.
Example of modifying the table records
<sqltransaction> <atomic> <update table='ctipoter'> <row> <columns> <nomter>TEST</nomter> </columns> <where>codigo = 'TST'</where> </row> </update> </atomic> </sqltransaction> [editar]
Example of removing records from a table
<sqltransaction> <atomic> <delete table='ctipoter' where="codigo = 'TST'"/> </atomic> </sqltransaction>
Example of invoking an embedded xsql-script that returns a vtable
<call> <![CDATA[ <xsql-script> <body> <return> <vtable> <select> <columns> * </columns> <from table = 'ctipoter'/> </select> </vtable> </return> </body> </xsql-script> ]]> </call>
Example of invoking a cataloged xsql-script
<call name = 'gcompedh'> <args> <arg>V</arg> <arg>1940738</arg> </args> </call>
1.3 Perl Client
The following example shows a call to service SOAPXMLServer.executeXML(String database, String code)
1.3.1 Requisitos previos
Require the package SOAP::Lite
1.3.2 Execution
perl soap.pl
1.3.3 Example code
#!/usr/bin/perl -w use SOAP::Lite; #use SOAP::Lite +trace => 'debug'; while ( 1 eq 1 ){ print "Introduzca ubicación: "; $codubi = <STDIN>; chomp ($codubi); print "Introduzca propuesta: "; $propuesta = <STDIN>; chomp ($propuesta); $xml = '<call name="user_xsql_script"><args><arg name="p_docser">'.$propuesta.'</arg><arg name="p_codubi">'.$codubi.'</arg></args></call>'; my $soap_response = SOAP::Lite -> uri('urn:SOAPXMLServer') -> proxy('http://www.mydeister.com/soap/servlet/rpcrouter') -> executeXML(SOAP::Data->type('string')->name('database')->value('demo_test'),SOAP::Data->type('string')->name('code')->value($xml)); my $res = $soap_response->valueof('//errmessg'); my $trc = $soap_response->valueof('//errtrace'); my $ok = $soap_response->valueof('//_constant_1_'); if (defined($res)) { print "\n==================================================================\n"; print " $res \n"; print " $trc \n"; # Solo imprimir en caso de debug print "\n==================================================================\n"; } if (defined($ok)) { print "\n\n$ok \n\n"; } }
1.4 PHP Client
The following example shows a call to service SOAPXMLServer.executeXML(String database, String code)
1.4.1 Example code
<?php // The XML command to execute in the remote server $xml = '<call name="garticul_getubi"><args><arg name="p_codalm">0925</arg><arg name="p_codart">98044582</arg></args></call>'; // Create the soap instance $client = new SoapClient(null, array( 'location' => "http://192.168.10.10/soap/servlet/rpcrouter", 'uri' => "urn:SOAPXMLServer", 'login' => "myuserid", 'password' => "myuserpasswd", 'trace' => 1, ) ); // Make the call $return = $client->__soapCall("executeXML", array("database"=>"mydbname","code"=>$xml)); // Print the resulting data print_r( $return ); ?>
1.4.2 RAW Java client
When in Java you do not have a serialization library such as Apache SOAP (on an Android device), you can make soap messages directly and negotiate with the server in direct http protocol. This mencanism requires more advanced knowledge of Java and interoperability with SOAP. The serialization and deserialization process can be especially complex.
Example3
The following example shows a service call routine SOAPXMLServer.executeXML(String database, String xml_code)
rem =========================================================================== rem rem SOAPExecuteXMLClient1.bat rem rem Executes a call to the SOAPXMLServer client for executeSQL commands: rem Element executeXML(String database, String xml_code) rem rem =========================================================================== set JDK_HOME="C:\Program Files\Java\jdk1.8.0_05" %JDK_HOME%\bin\javac SOAPExecuteXMLClient1.java %JDK_HOME%\bin\java SOAPExecuteXMLClient1 PAUSE
rem =========================================================================== rem rem SOAPExecuteXMLClient1.bat rem rem Execute a call to the client SOAPXMLServer for executeSQL commands: rem Element executeXML(String database, String xml_code) rem rem =========================================================================== set JDK_HOME="C:\Program Files\Java\jdk1.8.0_05" %JDK_HOME%\bin\javac SOAPExecuteXMLClient1.java %JDK_HOME%\bin\java SOAPExecuteXMLClient1 PAUSE
/* * @(#)SOAPExecuteXMLClient1.java * org.w3c.dom.Element executeXML(String database, String xml_code) * * */ import java.util.Base64; // java.io import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; // java.net import java.net.URL; import java.net.HttpURLConnection; // java.util.zip import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPInputStream; public class SOAPExecuteXMLClient1 { protected static final String URI_XML_LITERALXML = "http://xml.apache.org/xml-soap/literalxml"; protected static final String URI_SOAP_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/"; protected static final String WEBSTUDIO_RPCROUTER = "/soap/servlet/rpcrouter"; public static void main(String[] args) throws Exception { String host = "www.example.com"; String database = "dbmstest"; String user = "usertest"; String password = "passtest"; /* create table soaptest ( f00_serial serial NOT NULL, f01_char char(10), f02_date date, f03_intvl interval hour to second, f04_dtime datetime year to second, f05_boolean boolean, f06_smallint smallint, f07_int integer, f08_int8 int8, f09_dec decimal(14, 2), f10_smfloat smallfloat, f11_float float, f12_money money(14, 2), f13_real real, f14_numeric numeric, f15_varchar varchar(255), f16_nchar nchar(20), f17_lvarchar lvarchar, f18_clob clob, f19_blob blob, f20_text text, f21_byte byte ); create unique index p_soaptest on soaptest (f00_serial); alter table soaptest add constraint primary key (f00_serial) constraint p_soaptest; */ byte[] _bytes = "CLOB type column".getBytes(); String f19_blob = Base64.getEncoder().encodeToString(_bytes); String f20_text = "Texto largo TEXT, debe ser byte[]"; byte[] _bytes3 = new byte[] { 0x00, 0x01, 0x02 }; String f21_byte = Base64.getEncoder().encodeToString(_bytes3); String xmltran = "<sqltransaction>\n" + " <insert table='soaptest'>\n" + " <row>\n"+ " <f00_serial>" + new Integer(0) +"</f00_serial>\n" + " <f01_char>ABCDEFG</f01_char>\n" + " <f02_date dd='10' mm='6' yy='2015'></f02_date>\n" + " <f03_intvl></f03_intvl>\n" + " <f04_dtime dd='10' mm='6' yy='2015' HH='10' MM='24' SS='6'></f04_dtime>\n" + " <f05_boolean>"+new Boolean(true)+"</f05_boolean>\n" + " <f06_smallint>"+new Short((short)10)+"</f06_smallint>\n" + " <f07_int>"+new Integer(20)+"</f07_int>\n" + " <f08_int8>"+new Long(20)+"</f08_int8>\n" + " <f09_dec>"+new Double(30.1234)+"</f09_dec>\n" + " <f10_smfloat>"+new Float(30.1234)+"</f10_smfloat>\n" + " <f11_float>"+new Double(30.1234)+"</f11_float>\n" + " <f12_money>"+new Double(30.1234)+"</f12_money>\n" + " <f13_real>"+new Double(30.1234)+"</f13_real>\n" + " <f14_numeric>"+new Double(30.1234)+"</f14_numeric>\n" + " <f15_varchar>Test de varchar</f15_varchar>\n" + " <f16_nchar>Campo de texto largo tipo lvarchar, debe ser String</f16_nchar>\n" + " <f17_lvarchar>Test de nchar</f17_lvarchar>\n" + " <f18_clob>Campo de texto largo tipo CLOB, puede ser String o byte[]</f18_clob>\n" + " <f19_blob>"+f19_blob+"</f19_blob>\n" + " <f20_text>"+f20_text+"</f20_text>\n" + " <f21_byte>"+f21_byte+"</f21_byte>\n" + " </row>\n" + " </insert>\n" + "</sqltransaction>\n"; try { String res = executeXML(host, user, password, database, xmltran); System.err.println(res); } catch (Exception ex) { ex.printStackTrace(); } System.err.println("End test."); } public final static String executeXML( String host, String user, String password, String database, String stmt ) throws IOException, org.xml.sax.SAXException, javax.xml.parsers.ParserConfigurationException { StringBuffer buf = new StringBuffer(); buf.append("<?xml version='1.0' encoding='UTF-8'?>\n"); buf.append("<SOAP-ENV:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>\n"); buf.append("<SOAP-ENV:Body>\n"); buf.append("<ns1:executeXML xmlns:ns1='urn:SOAPXMLServer' SOAP-ENV:encodingStyle='" + URI_XML_LITERALXML + "'>\n"); buf.append("<database xsi:type='xsd:string' SOAP-ENV:encodingStyle='" + URI_SOAP_ENCODING + "'>" + database + "</database>\n"); buf.append("<sql xsi:type='xsd:string' SOAP-ENV:encodingStyle='" + URI_SOAP_ENCODING + "'>" + encodeXML(stmt) + "</sql>\n"); buf.append("</ns1:executeXML>\n"); buf.append("</SOAP-ENV:Body>\n"); buf.append("</SOAP-ENV:Envelope>\n"); InputStream in = SOAPCall(host, user, password, buf.toString()); if (in == null) return null; // Convert response to text InputStreamReader is = new InputStreamReader(in); StringBuilder sb = new StringBuilder(); BufferedReader br = new BufferedReader(is); String read = br.readLine(); while(read != null) { sb.append(read); sb.append("\n"); read = br.readLine(); } return sb.toString(); } public final static InputStream SOAPCall( String host, String user, String password, String xmlmsg ) throws IOException, org.xml.sax.SAXException, javax.xml.parsers.ParserConfigurationException { URL u = new URL("http", host, WEBSTUDIO_RPCROUTER); HttpURLConnection connection = (HttpURLConnection)u.openConnection(); HttpURLConnection.setFollowRedirects(true); connection.setDoInput(true); connection.setDoOutput(true); connection.setUseCaches(false); connection.setRequestMethod("POST"); connection.setAllowUserInteraction(false); connection.setRequestProperty("Accept-Encoding", "gzip"); connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8"); connection.setRequestProperty("Content-Encoding", "gzip"); String token = user + ":" + password; String realm= Base64.getEncoder().encodeToString(token.getBytes()); connection.setRequestProperty("Authorization", "Basic " + realm); connection.setRequestProperty("SOAPAction", ""); OutputStream out = connection.getOutputStream(); OutputStreamWriter wout = new OutputStreamWriter(new GZIPOutputStream(out)); wout.write(xmlmsg); wout.flush(); wout.close(); String contentEncoding = connection.getContentEncoding(); int contentLength = connection.getContentLength(); String contentType = connection.getContentType(); InputStream in; if (connection.getResponseCode() != 200) { // Get the ERROR Stream if ("gzip".equals(contentEncoding)) in = new GZIPInputStream(connection.getErrorStream()); else in = connection.getErrorStream(); } else { if ("gzip".equals(contentEncoding)) in = new GZIPInputStream(connection.getInputStream()); else in = connection.getInputStream(); } return in; } /************************************************************************** * * * * XML ENCODE * * * ***************************************************************************/ public final static String encodeXML(String input) { if (input == null) return ""; int size = input.length(); StringBuilder buf = new StringBuilder(size + size / 8); for(int i = 0; i < size; i++) { char c = input.charAt(i); switch(c) { // To avoid: An invalid XML character (Unicode: 0x1a) was found // It occurs when someone pastes in text that contains specific unicode characters that are invalid in XML case 0x1A: buf.append(" "); break; case '"': buf.append("""); break; // La ' ha de ser codificable en un attribute per exemple com ' // I en un texte, no pasa res (sembla) si es codificada case '\'': buf.append("'"); break; case '>': buf.append(">"); break; case '<': buf.append("<"); break; case '&': buf.append("&"); break; default: buf.append(c); } } return buf.toString(); } }