giacomo     01/06/12 07:51:18

  Modified:    webapp   sitemap.xmap
  Added:       src/org/apache/cocoon/generation StreamGenerator.java
               src/org/apache/cocoon/util PostInputStream.java
               webapp/docs/samples/stream OrderPage.xml ReadMeAdd.txt
                        telnet.txt
  Log:
  Added StreamGenerator and samples
  Submitted by: kingadziembowska <[EMAIL PROTECTED]>
  
  Revision  Changes    Path
  1.12      +15 -25    xml-cocoon2/webapp/sitemap.xmap
  
  Index: sitemap.xmap
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/webapp/sitemap.xmap,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -u -r1.11 -r1.12
  --- sitemap.xmap      2001/05/29 20:11:38     1.11
  +++ sitemap.xmap      2001/06/12 14:51:16     1.12
  @@ -17,6 +17,7 @@
      <map:generator  name="velocity"    
src="org.apache.cocoon.generation.VelocityGenerator"/>
      <map:generator  name="html"        
src="org.apache.cocoon.generation.HTMLGenerator" label="content"/>
      <map:generator  name="jsp"         
src="org.apache.cocoon.generation.JspGenerator"/>
  +   <map:generator  name="stream"      
src="org.apache.cocoon.generation.StreamGenerator"/>
     </map:generators>
   
     <map:transformers default="xslt">
  @@ -346,31 +347,6 @@
       <map:read src="docs/samples/{1}.png" mime-type="image/png"/>
      </map:match>
   
  -   <!--
  -    This pipeline is responsable for generating the images for the navigation
  -    bar. It uses the navimage.xsp to generate an SVG document which contains
  -    the text for the image from the request URI passed as a parameter. The
  -    requested language is evaluated by the LangSelect action. The text
  -    represents a key into the i18n dictionary for all navigation items. At
  -    the end the generated SVG is serialized as a PNG image.
  -    This pipeline is fully cachable and thus an image depends only on
  -    the text id and the laguage used and is generated once for each 
combination.
  -   -->
  -   <map:match type="regexp" pattern="i18n/images/(.*)_(.*)_(.*).png">
  -    <map:generate type="serverpages" src="docs/samples/i18n/navimages.xsp">
  -     <map:parameter name="text" value="{1}"/>
  -     <map:parameter name="lang" value="{2}"/>
  -     <map:parameter name="kind" value="{3}"/>
  -    </map:generate>
  -    <map:transform type="i18n" src="docs/samples/i18n/nav_trans.xml">
  -     <map:parameter name="lang" value="{2}"/>
  -     <map:parameter name="default_lang" value="en"/>
  -     <map:parameter name="available_lang_1" value="en"/>
  -     <map:parameter name="available_lang_2" value="de"/>
  -    </map:transform>
  -    <map:serialize type="svg2png"/>
  -   </map:match>
  -
      <!-- =========================== Dynamic ================================ 
-->
      <map:match pattern="xsp/*">
       <map:generate type="serverpages" src="docs/samples/xsp/{1}.xsp"/>
  @@ -425,6 +401,20 @@
           <map:parameter name="view-source" 
value="docs/samples/session/{1}.xsp"/>
        </map:transform>
        <map:serialize/>
  +   </map:match>
  +
  +   <!-- ========================== Stream ================================= 
-->
  +   <map:match pattern="request1">
  +     <map:generate type="stream">
  +       <map:parameter name="form-name" value="Foo"/>
  +     </map:generate>
  +     <map:serialize type="xml"/>
  +   </map:match>
  +
  +   <map:match pattern="Order">
  +     <map:generate src="docs/samples/stream/OrderPage.xml"/>
  +     <map:transform src="stylesheets/dynamic-page2html.xsl"/>
  +     <map:serialize type="html"/>
      </map:match>
   
      <!-- ========================== XSP Sources 
============================== -->
  
  
  
  1.1                  
xml-cocoon2/src/org/apache/cocoon/generation/StreamGenerator.java
  
  Index: StreamGenerator.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   
*****************************************************************************/
  package org.apache.cocoon.generation;
  
  import java.io.StringReader;
  import java.io.IOException;
  import java.util.Map;
  
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.ResourceNotFoundException;
  import org.apache.cocoon.Roles;
  import org.apache.cocoon.components.parser.Parser;
  import org.apache.cocoon.environment.http.HttpRequest;
  import org.apache.cocoon.environment.Source;
  import org.apache.cocoon.environment.SourceResolver;
  import org.apache.cocoon.util.PostInputStream;
  
  import org.apache.avalon.excalibur.pool.Poolable;
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.parameters.Parameters;
  
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  
  /**
   *
   * The <code>StreamGenerator</code> is a class that reads XML from a request 
InputStream
   * and generates SAX Events.
   * For the POST requests with mimetype of application/x-www-form-urlencoded 
the xml data is
   * expected to be associated with the name specified in the sitemap parameter.
   * For the POST requests with mimetypes: text/plain, text/xml, 
application/xml the xml data is in the body of teh POST
   * request and its length is specified by the value returned by 
getContentLength() method.
   * The StreamGenerator uses helper org.apache.cocoon.util.PostInputStream 
class for InputStream reading operations.
   * At the time that Parser is reading the data out of InputStream - Parser 
has no knowledge about the length of data to be read.
   * The only way to signal to the Parser that all data was read from the 
InputStream is to control reading operation - PostInputStream- and to return to
   * the requestor -1 when the number of bytes read is equal to the 
getContentLength() value.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Kinga Dziembowski</a>
   * @version $Revision: 1.1 $ $Date: 2001/06/12 14:51:17 $
   */
  public class StreamGenerator extends ComposerGenerator {
  
      public static final String CLASS = StreamGenerator.class.getName();
  
      /** The parameter holding the name associated with the xml data  **/
      public static final String FORM_NAME = "form-name";
      /** The input source */
      private InputSource inputSource;
      /** The system ID of the input source */
      private String      systemID;
  
      /**
       * Set the current <code>ComponentManager</code> instance used by this
       * <code>Composable</code>.
       */
      public void compose(ComponentManager manager) {
          super.compose(manager);
      }
  
      /**
      * Recycle this component.
      * All instance variables are set to <code>null</code>.
      */
      public void recycle() {
          super.recycle();
          this.inputSource = null;
          this.systemID = null;
      }
  
      /**
      * Setup the stream generator.
      */
      public void setup(SourceResolver resolver, Map objectModel, String src, 
Parameters par)
          throws ProcessingException, SAXException, IOException {
          super.setup(resolver, objectModel, src, par);
      }
  
      /**
      * Generate XML data out of request InputStream.
      */
      public void generate()  throws IOException, SAXException, 
ProcessingException {
          Parser parser = null;
          String parameter = parameters.getParameter(StreamGenerator.FORM_NAME, 
null);
          int len = 0;
          try {
              HttpRequest request = (HttpRequest) 
objectModel.get(Constants.REQUEST_OBJECT);
              if 
(request.getContentType().equals("application/x-www-form-urlencoded")) {
                  String sXml = request.getParameter(parameter);
                  inputSource = new InputSource(new StringReader(sXml));
              } else if (request.getContentType().equals("text/plain")
                      || request.getContentType().equals("text/xml")
                      || request.getContentType().equals("application/xml")) {
                      len = request.getContentLength();
                      if (len > 0) {
                          PostInputStream anStream = new 
PostInputStream(request.getInputStream(), len);
                          inputSource = new InputSource(anStream);
                      } else {
                          throw new IOException("getContentLen() == 0");
                      }
                  } else {
                      throw new IOException("Unexpected getContentType(): " + 
request.getContentType());
                  }
              }
              getLogger().debug("processing stream ContentType= " + 
request.getContentType() + "ContentLen= " + len);
  
              parser = (Parser)this.manager.lookup(Roles.PARSER);
              parser.setContentHandler(super.contentHandler);
              parser.setLexicalHandler(super.lexicalHandler);
              parser.parse(this.inputSource);
          } catch (IOException e) {
              getLogger().error("StreamGenerator.generate()", e);
              throw new ResourceNotFoundException("StreamGenerator could not 
find resource", e);
          } catch (SAXException e) {
              getLogger().error("StreamGenerator.generate()", e);
              throw(e);
          } catch (Exception e){
              getLogger().error("Could not get parser", e);
              throw new ProcessingException("Exception in 
StreamGenerator.generate()",e);
          } finally {
              if (parser != null) this.manager.release((Component) parser);
          }
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/org/apache/cocoon/util/PostInputStream.java
  
  Index: PostInputStream.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   
*****************************************************************************/
  package org.apache.cocoon.util;
  
  import java.io.InputStream;
  import java.io.IOException;
  /**
   * The class PostInputStream is a wrapper for InputStream associated with 
POST message.
   * It allows to control read operation, restricting the number of bytes read 
to the value returned by getContentLen() method.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Kinga Dziembowski</a>
   * @version $Id: PostInputStream.java,v 1.1 2001/06/12 14:51:17 giacomo Exp $
   */
  
  public class PostInputStream extends InputStream {
  
      /**
      * Class name
      */
      public static final String CLASS = PostInputStream.class.getName();
  
      /** The real InputStream object */
      private InputStream m_inputStream = null;
  
      /** The length of InputStream */
      private int m_contentLen = 0;
  
      /** The number of bytes read */
      protected int m_bytesRead = 0;
  
  
      /**
      * Creates a PostInputStream
      */
      public PostInputStream() {
          super();
      }
      /**
      * Creates a <code>PostInputStream</code> based on a real InputStream 
object with the specified
      * post message body length. Saves its  argument, the input stream
      * <code>m_inputStream</code>, for later use.
      *
      * @param   input     the underlying input stream.
      * @param   len   the post message body length.
      * @exception IllegalArgumentException  len <= 0.
      */
  
      public PostInputStream(final InputStream input, final int len) throws 
IllegalArgumentException {
          super();
          init(input, len );
      }
      /**
      * Sets the underlying input stream and contentLen value .
      *
      * @param inputStream the input stream; can not be null.
      * @param len the post message body length.
      *
      * @throws IllegalArgumentException
      */
      protected void init(final InputStream input, final int len) throws 
IllegalArgumentException {
          if (len <= 0) {
              throw new IllegalArgumentException("contentLen <= 0 ");
          }
          this.m_inputStream = input;
          this.m_contentLen = len;
      }
  
      /**
      * Sets the underlying input stream and contentLen value .
      *
      * @param inputStream the input stream; can not be null.
      * @param len the post message body length.
      *
      * @throws IOException
      */
      public synchronized void setInputStream(final InputStream input, final 
int len) throws IOException {
          if (m_inputStream != null) {
              close();
          }
          init(input, len);
      }
      /**
      * Returns the underlying input stream.
      *
      * @return inputStream the underlying InputStream.
      */
      public InputStream getInputStream() {
          return( m_inputStream );
      }
  
      /**
      * Returns the post message body length.
      *
      * @return m_contentLen;
      */
  
      public int getContentLen() {
          return( m_contentLen );
      }
  
      /**
      * Reads the next byte from the input stream.  If the end of the stream 
has been reached, this method returns -1.
      *
      * @return the next byte or -1 if at the end of the stream.
      *
      * @throws IOException
      */
      public synchronized int read() throws IOException {
  
          checkOpen();
          if (m_bytesRead == m_contentLen) {
              return -1;
          }
          int byt =  m_inputStream.read();
          if (byt != -1) {
             m_bytesRead++;
          }
          return byt;
      }
  
      /**
      * Reads bytes from this byte-input stream into the specified byte array,
      * starting at the given offset.
      *
      * <p> This method implements the general contract of the corresponding
      * <code>[EMAIL PROTECTED] InputStream#read(byte[], int, int) read}</code> 
method of
      * the <code>[EMAIL PROTECTED] InputStream}</code> class.
      * This method delegetes tre read operation to the underlying InputStream 
implementation class but it
      * controlls the number of bytes read from the stream.In the remote 
situation the underlying InputStream has no knowledge of
      * the length of the stream and the notion of the "end" is undefined. This 
wrapper class has a knowledge of the
      * length of data send by the requestor by the means of contentLength. 
This method returns the number of bytes read and
      * accumulates the total number of bytes read in m_bytesRead. When the 
m_bytesRead is equal to the specified contentLength
      * value the method returns returns -1 to signal the end of data.
      *
      * @param buffer the byte array to read into; can not be null.
      * @param offset the starting offset in the byte array.
      * @param len the maximum number of bytes to read.
      *
      * @return     the number of bytes read, or <code>-1</code> if the end of
      *             the stream has been reached.
      * @exception  IOException  if an I/O error occurs.
      */
  
      public synchronized int read(byte[] buffer, int offset, int len) throws 
IOException {
          checkOpen();
          if (m_bytesRead == m_contentLen) {
              return -1;
          }
          int num = m_inputStream.read(buffer, offset, len);
          if (num > 0) {
              m_bytesRead += num;
          }
          return num;
      }
  
      public synchronized int read(byte[] buffer) throws IOException {
  
          return read( buffer, 0, buffer.length);
      }
  
  
      /**
      * Checks to see if this stream is closed; if it is, an IOException is 
thrown.
      *
      * @throws IOException
      */
      protected void checkOpen() throws IOException {
          if (m_inputStream == null) {
              throw new IOException("InputStream closed");
          }
      }
  
      /**
           * See the general contract of the <code>skip</code>
       * method of <code>InputStream</code>.
       * Delegates execution to the underlying InputStream implementation class.
       * Checks to see if this stream is closed; if it is, an IOException is 
thrown.
       * @param      n   the number of bytes to be skipped.
       * @return     the actual number of bytes skipped.
       * @exception  IOException  if an I/O error occurs.
       */
      public synchronized long skip(long n) throws IOException {
          checkOpen();
          return m_inputStream.skip(n);
      }
  
      /**
      * Returns the number of bytes available from this input stream that can 
be read without the stream blocking.
      * Delegates execution to the underlying InputStream implementation class.
      * @return available the number of available bytes.
      *
      * @throws IOException
      */
      public synchronized int available() throws IOException {
          checkOpen();
          return m_inputStream.available();
      }
  
      /**
      * Tests if this input stream supports the <code>mark</code>
      * and <code>reset</code> methods. The <code>markSupported</code>
      * method of <code>BufferedInputStream</code> returns
      * <code>false</code>.
      *
      * @return  a <code>boolean</code> indicating if this stream type supports
      *          the <code>mark</code> and <code>reset</code> methods.
      * @see     java.io.InputStream#mark(int)
      * @see     java.io.InputStream#reset()
      */
      public boolean markSupported() {
          return false;
      }
  
      /**
      * Closes this input stream by closing the underlying stream and marking 
this one as closed.
      *
      * @throws IOException
      */
      public synchronized void close() throws IOException {
          if (m_inputStream == null) {
              return;
          }
          m_inputStream.close();
          m_inputStream = null;
          m_contentLen = 0;
          m_bytesRead = 0;
      }
  
      /**
      * Returns a String representation of this.
      *
      * @return string the String representation of this.
      */
      public String toString() {
          return getClass().getName() + "[inputStream=" + m_inputStream + ",  
contentLen=" + m_contentLen + "bytesRead=" + m_bytesRead + "]";
      }
  }
  
  
  1.1                  xml-cocoon2/webapp/docs/samples/stream/OrderPage.xml
  
  Index: OrderPage.xml
  ===================================================================
  <page>
   <title>B2B processing</title>
    <content>
     <FORM action="http://localhost:8080/cocoon/request1"; id="FORM1" 
method="post" name="FORM1">
        <para>Input your XML documet here:</para>
        <TEXTAREA cols="80" id="TEXTAREA1" name="Foo" rows="60">&lt;?xml 
version="1.0"?&gt;
                &lt;Orders&gt;
                &lt;OrderID&gt;20259&lt;/OrderID&gt;
                &lt;CustomerID&gt;WWWWWWW&lt;/CustomerID&gt;
                &lt;EmployeeID&gt;6&lt;/EmployeeID&gt;
                &lt;OrderDate&gt;2001-05-05 00:00:00&lt;/OrderDate&gt;
                &lt;RequiredDate&gt;2001-06-05 00:00:00&lt;/RequiredDate&gt;
                &lt;ShippedDate&gt;2001-06-01 00:00:00&lt;/ShippedDate&gt;
                &lt;ShipVia&gt;1&lt;/ShipVia&gt;
                &lt;Freight&gt;11.6100&lt;/Freight&gt;
                &lt;ShipName&gt;Thoms White&lt;/ShipName&gt;
                &lt;ShipAddress&gt;Somestr. 48&lt;/ShipAddress&gt;
                &lt;ShipCity&gt;Munster&lt;/ShipCity&gt;
                &lt;ShipRegion&gt;West&lt;/ShipRegion&gt;
                &lt;ShipPostalCode&gt;00000&lt;/ShipPostalCode&gt;
                &lt;ShipCountry&gt;Germany&lt;/ShipCountry&gt;
                &lt;OrderDetails&gt;
                        &lt;OrderID&gt;20259&lt;/OrderID&gt;
                        &lt;ProductID&gt;51&lt;/ProductID&gt;
                        &lt;UnitPrice&gt;42.4000&lt;/UnitPrice&gt;
                        &lt;Quantity&gt;40&lt;/Quantity&gt;
                        &lt;Discount&gt;0.0&lt;/Discount&gt;
                &lt;/OrderDetails&gt;
                &lt;OrderDetails&gt;
                                &lt;OrderID&gt;20259&lt;/OrderID&gt;
                                &lt;ProductID&gt;14&lt;/ProductID&gt;
                                &lt;UnitPrice&gt;18.6000&lt;/UnitPrice&gt;
                                &lt;Quantity&gt;9&lt;/Quantity&gt;
                                &lt;Discount&gt;0.0&lt;/Discount&gt;
                &lt;/OrderDetails&gt;
                &lt;OrderDetails&gt;
                                &lt;OrderID&gt;20259&lt;/OrderID&gt;
                                &lt;ProductID&gt;7&lt;/ProductID&gt;
                                &lt;UnitPrice&gt;12.4000&lt;/UnitPrice&gt;
                                &lt;Quantity&gt;30&lt;/Quantity&gt;
                                &lt;Discount&gt;0.0&lt;/Discount&gt;
                &lt;/OrderDetails&gt;
                &lt;Customers&gt;
                        &lt;CustomerID&gt;WWWWWWW&lt;/CustomerID&gt;
                        &lt;CompanyName&gt;Thomas White&lt;/CompanyName&gt;
                        &lt;ContactName&gt;Karin Black&lt;/ContactName&gt;
                        &lt;ContactTitle&gt;Marketing 
Manager&lt;/ContactTitle&gt;
                        &lt;Address&gt;Somestr. 48&lt;/Address&gt;
                        &lt;City&gt;Munster&lt;/City&gt;
                        &lt;Region&gt;West&lt;/Region&gt;
                        &lt;PostalCode&gt;00000&lt;/PostalCode&gt;
                        &lt;Country&gt;Germany&lt;/Country&gt;
                        &lt;Phone&gt;xxxx-yyyyyy&lt;/Phone&gt;
                        &lt;Fax&gt;xxxx-yyyyyy&lt;/Fax&gt;
                &lt;/Customers&gt;
        &lt;/Orders&gt;
        </TEXTAREA>
        
        <INPUT id="submit1" name="submit1" type="submit" value="Submit"/>
        </FORM>
        </content>
        </page>
  
  
  
  1.1                  xml-cocoon2/webapp/docs/samples/stream/ReadMeAdd.txt
  
  Index: ReadMeAdd.txt
  ===================================================================
                   Hewlett-Packard Bluestone Cocoon Project
  
                                 @version@
  
  
    What is being added?
    --------------------
  
  �     StreamGenerator
  �     PostInputStream
     
  StreamGenerator
  The StreamGenerator is a class that reads XML from an HttpRequest InputStream 
and generates SAX Events. StreamGenerator expects XML data coming as POST 
message. 
  
  For POST requests with mimetype of application/x-www-form-urlencoded, the xml 
data expects to be associated with the name specified in the sitemap parameter.
  
  For POST requests with mimetypes: text/plain, text/xml, application/xml the 
xml data is in the body of the POST request and its length is specified by the 
value returned by getContentLength() method.
    
  PostInputStream
  The StreamGenerator uses helper class org.apache.cocoon.util.PostInputStream 
for InputStream reading operations. At the time that Parser reads the data out 
of InputStream - Parser has no knowledge about the length of data to be    
read. The only way to signal to the Parser that all data was read from the 
InputStream is to control reading   operation - PostInputStream- and to return 
to the requestor -1 when the number of bytes read is equal to the 
getContentLength() value.
    
  
  Installation Instructions
  ----------------------------
  TO VIEW ABOVE COCOON ELEMENTS "IN ACTION":
    
  Unzip the attached file. The necessary elements will "fall into place" within 
the Cocoon code. Compile it using instruction in Cocoon install file. Since the 
generator is a generic object, i.e. it can process any stream out of the POST 
message there are two ways to see StreamGenerator in action:
    1. To invoke URL http://localhost:8080/cocoon/Order
    2. To use telnet program to generate POST request
     
  The first option is not a "pure" stream invocation, but it is quick way to 
observe desired effects. The result of this invocation is a form containing the 
XML document embedded in the textarea of the form. Submission of this form will 
invoke StreamGenerator. The testarea name/value par is specified as a parameter 
in the sitemap definition for the StreamGenerator. The expected result is the 
submitted xml document send back to the browser.
    
  The second or "pure" option of testing StreamGenerator "in action," requires 
the use of Telnet program or any other process able to generate correct POST 
message. The procedure is:
  �     To invoke telnet, connect to localhost 8080 and to use content of 
telnet.txt file as a post message. 
  �     Here, the Copy-Paste method should be used.
  �     Remember to hit the enter button twice enter after the contents of the 
post are set in telnet.
  
  It is important because Content-len is calculated assuming two "enter" in the 
end of http message. Once again, the performed task results in the mirror of 
the original document being sent back to the requestor. 
  
  The "pure" stream generation can be observed using the telnet utility where 
you can invoke a message targeting my processing. Any other method is good (URL 
object connection) as long the message is well formed.
  
  
  Compatibility Issues
  ------------------------
  
  The attached code was tested and is compatible with the Cocoon codebase 
ver.2.0a7 taken from CVS Repository 5/26/2001. 
  The code was tested  on  Windows 2000 and  NT 4.0  using Tomcatt 4.0-b5 and 
newest Bluestone HP  application server. 
  
  
  
  1.1                  xml-cocoon2/webapp/docs/samples/stream/telnet.txt
  
  Index: telnet.txt
  ===================================================================
  POST /cocoon/request1 HTTP/1.1
  Content-Type: text/plain
  Content-Length:1513
  
  <?xml version="1.0"?>
  <Orders>
        <OrderID>20259</OrderID>
        <CustomerID>WWWWWWW</CustomerID>
        <EmployeeID>6</EmployeeID>
        <OrderDate>2001-05-05 00:00:00</OrderDate>
        <RequiredDate>2001-06-05 00:00:00</RequiredDate>
        <ShippedDate>2001-06-01 00:00:00</ShippedDate>
        <ShipVia>1</ShipVia>
        <Freight>11.6100</Freight>
        <ShipName>Thoms White</ShipName>
        <ShipAddress>Somestr. 48</ShipAddress>
        <ShipCity>Munster</ShipCity>
        <ShipRegion>West</ShipRegion>
        <ShipPostalCode>00000</ShipPostalCode>
        <ShipCountry>Germany</ShipCountry>
        <OrderDetails>
                <OrderID>20259</OrderID>
                <ProductID>51</ProductID>
                <UnitPrice>42.4000</UnitPrice>
                <Quantity>40</Quantity>
                <Discount>0.0</Discount>
        </OrderDetails>
        <OrderDetails>
                <OrderID>20259</OrderID>
                <ProductID>14</ProductID>
                <UnitPrice>18.6000</UnitPrice>
                <Quantity>9</Quantity>
                <Discount>0.0</Discount>
        </OrderDetails>
        <OrderDetails>
                <OrderID>20259</OrderID>
                <ProductID>7</ProductID>
                <UnitPrice>12.4000</UnitPrice>
                <Quantity>30</Quantity>
                <Discount>0.0</Discount>
        </OrderDetails>
        <Customers>
                <CustomerID>WWWWWWW</CustomerID>
                <CompanyName>Thomas White</CompanyName>
                <ContactName>Karin Black</ContactName>
                <ContactTitle>Marketing Manager</ContactTitle>
                <Address>Somestr. 48</Address>
                <City>Munster</City>
                <Region>West</Region>
                <PostalCode>00000</PostalCode>
                <Country>Germany</Country>
                <Phone>xxxx-yyyyyy</Phone>
                <Fax>xxxx-yyyyyy</Fax>
        </Customers>
  </Orders>
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     [EMAIL PROTECTED]
To unsubscribe, e-mail:          [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to