Share via


Documentos de Office de Web Service-Enabled XML

 

Chris Lovett
Microsoft Corporation

19 de marzo de 2001

Descargue Xml03192001.exe.

¿Está listo para un matrimonio con microsoft Office XP y servicios web .NET? En un mundo en red de comercio electrónico B2B, ¿por qué no entregar la eficacia de los servicios web al usuario final mediante la integración del flujo de trabajo del proceso de negocio directamente en todo lo que hacen las personas desde su escritorio? ¿De qué hablo? Bueno, una hoja de cálculo de Excel que tiene un aspecto similar a la figura 1.

Figura 1. Hoja de cálculo de Excel habilitada para servicios web

Esto no es solo una hoja de cálculo normal. Usa UDDI para buscar direcciones de la empresa y usa un servicio web de catálogo para buscar información del producto. También realiza una transformación XML en el formato de hoja de cálculo XML para generar un formato de solicitud de pedido de compra pip 3 A4 de RosettaNet al hacer clic en el botón Enviar .

Cuando escribe el nombre de la empresa desde la que está comprando y, a continuación, hace clic en el botón Buscar , algún código VBA detrás de la hoja de cálculo realiza una llamada UDDI y rellena el resto de la sección de direcciones. Por ejemplo, escriba Microsoft, haga clic en Buscar y debería ver lo siguiente en los campos Comprar desde :

Ilustración 2. Comprar desde el campo

Cuando escribe una cantidad de, por ejemplo, 23 y, a continuación, el término Pear en el campo descripción, presione la tecla TAB, un código VBA consulta un servicio web de catálogo SOAP para ver si puede encontrar un producto coincidente y, a continuación, rellena los detalles. En este caso, he conectado el servicio web de catálogo a la base de datos Northwind, por lo que devuelve lo siguiente:

Figura 3. Análisis detallado de la parte del orden de la hoja de cálculo

En este caso, también ha rellenado la descripción y lo ha convertido en un vínculo que le lleva a una página HTML que le indica todo sobre ese producto.

Si se encuentra más de un producto y ninguno de ellos coincide exactamente con lo que ha escrito, se proporciona una lista desplegable de opciones. Por ejemplo, si escribe tofu, verá las siguientes opciones:

Figura 4. Ejemplo de varias opciones proporcionadas cuando no se encuentra una coincidencia exacta

Al seleccionar una de estas opciones, se proporcionan los detalles específicos.

Cuando haya terminado, haga clic en el botón Enviar y se generará el formato rosettaNet PIP 3 A4 XML Purchase Order (Pedido de compra XML de RosettaNet PIP 3 A4) y se enviará el pedido.

¿Cómo funciona todo esto?

Para examinar el código VBA detrás de la hoja de cálculo, vaya al menú Herramientas , seleccione Macro y, a continuación, Editor de Visual Basic. Hay un poco de código detrás de ThisWorkbook que reacciona a los cambios en la hoja de cálculo, en particular el evento Workbook_SheetChange borra un elemento de línea al eliminar la descripción y el evento Workbook_SheetSelectionChange llama a FindProduct() cuando se tabula fuera del campo Descripción en el campo SKU . Si FindProduct devuelve un XMLNode, los campos pertinentes se extraen de ese nodo para rellenar el resto de los detalles del elemento de línea.

Cómo funciona la llamada udDI find_business en mi artículo anterior UDDI: Un servicio web XML. Si se encuentra una empresa, las direccionesLines que se encuentran en la parte /businessInfo/contacts/contact/address/ de la respuesta UDDI se usan para rellenar el bloque de direcciones Comprar desde .

Servicio web de catálogo

La función FindProduct del módulo Catalogs llama a la dirección URL del servicio de catálogo con un parámetro de dirección URL que contiene el término de búsqueda que se va a buscar. Espera devolver una respuesta SOAP y comprobar primero si coincide con /Envelope/Body/Fault, si no es un error, continúa para abrir la <comprobación CatalogQueryResult> para ver si el atributo ProductName de algún elemento devuelto coincide con el término especificado. También crea la lista desplegable de opciones más abajo de la página fuera del área visible. Para ver cómo funciona la lista desplegable, vaya al menú Datos y seleccione Validación.

El servicio web de catálogo es muy sencillo. El punto de entrada .aspx simplemente crea un objeto CatalogSearch que se define en search.cs y llama a Execute, pasando el flujo de salida HttpResponse de la siguiente manera:

<%@Language="C#" src="search.cs"  Debug="true" %>
<%
   Response.ContentType = "text/xml";
   string term = Request.QueryString["term"];
   if (term != null) {
      CatalogSearch s = new CatalogSearch(term);
      s.Execute(output);
   } else {
      Response.Write("<Empty/>");
   }
%>

El método Execute es donde comienza la diversión. Se trata de código SQL Proveedor de datos administrados muy sencillo encapsulado en un objeto XmlTextWriter que devuelve los campos específicos de la instrucción SELECT de SQL. Por lo tanto, es básicamente un bucle while a través de DataReader, escribiendo en XmlTextWriter de la siguiente manera:

public void Execute(TextWriter stm)
{      
   XmlTextWriter xw = new XmlTextWriter(stm);
   xw.WriteStartElement("Envelope", "http://schemas..../envelope/");
   xw.WriteStartElement("Body", "http://schemas..../envelope/");
   try {
      String const = "server=localhost;uid=sa;pwd=;database=northwind";
      SQLConnection con = new SQLConnection(constr);
      con.Open();
      IDataReader reader;
      String query = "SELECT ProductName,UnitPrice,QuantityPerUnit," +
           "SupplierID,ProductID FROM Products WHERE " +
           "ProductName LIKE '%" + term + "%'";
      SQLCommand cmd = new SQLCommand(query, con);
      cmd.Execute(out reader);
      string funNamespace = "urn:schemas-b2b-fun:catalogs";
      xw.WriteStartElement("CatalogQueryResult", funNamespace);
      while (reader.Read())
      {
         xw.WriteStartElement("item");
         xw.WriteAttribute("ProductName", reader.GetString(0));
         xw.WriteAttrDecimal("UnitPrice", reader.GetDecimal(1));
         xw.WriteAttribute("UnitOfMeasure", reader.GetString(2));
         xw.WriteAttribute("SKU", "S"+reader.GetInt32(3)+
"-P"+reader.GetInt32(4));
         xw.WriteEndElement();
      }
      xw.WriteEndElement(); 
      con.Close();
   } catch (Exception e) {
      xw.WriteStartElement("Fault");
         xw.WriteElementString("faultcode","500");
         xw.WriteElementString("faultstring",e.ToString());
      xw.WriteEndElement();
   }
   xw.WriteEndElement();
   xw.WriteEndElement();
   xw.Close();
}

La dirección URL https://localhost/catalog/search.aspx?term=tofu devuelve el resultado siguiente:

<Envelope xmlns="https://schemas.xmlsoap.org/soap/envelope/">
<Body>
  <CatalogQueryResult xmlns="urn:schemas-b2b-fun:catalogs">
    <item ProductName="Tofu" UnitPrice="23.25" 
 UnitOfMeasure="40 - 100 g pkgs." SKU="S6-P14"/>
    <item ProductName="Longlife Tofu" UnitPrice="10" 
 UnitOfMeasure="5 kg pkg." SKU="S4-P74"/>
  </CatalogQueryResult>
</Body>
</Envelope>

Se trata de la manera más eficaz de sacar XML de SQL Server mediante .NET Frameworks. Con una medida muy aproximada, tengo unos 80 a 90 de estos por segundo en mi Dell PowerEdge 2400.

Botón Enviar

La función SendOrder() carga un documento XML desde una representación XML de un rango seleccionado de celdas de la hoja de cálculo. Esto se hace con las siguientes líneas mágicas de código VBA:

With ActiveSheet 
  Set sourcexml = New MSXML2.DOMDocument
  sourcexml.loadXML .Range("B1:N34").value(xlRangeValueXMLSpreadsheet)
End With

Esto devuelve un gran fragmento de XML que describe completamente todo sobre ese rango de celdas de la hoja de cálculo. A continuación se muestra un fragmento del fragmento de XML:

<Workbook>
    <Worksheet>
        <Table>
            <Row>
                <Cell ss:StyleID="s23"><Data ss:Type="Number">23</Data>
<NamedCell ss:Name="Item"/></Cell>
 <Cell ss:MergeAcross="4" ss:StyleID="m31209522" 
ss:HRef="http://eshop.msn.com/category.asp?catId=170">
<Data ss:Type="String">Uncle Bob's Organic Dried 
Pears</Data></Cell>
<Cell ss:StyleID="s52">
<Data ss:Type="String">S3-P7</Data></Cell>
                <Cell ss:StyleID="s26">
<Data ss:Type="Number">30</Data>
<NamedCell ss:Name="UnitPrice"/></Cell>
                <Cell ss:StyleID="s27">
<Data ss:Type="String">12 - 1 lb pkgs.</Data></Cell>
<Cell ss:StyleID="s37">
<Data ss:Type="Number">690</Data></Cell>
                <Cell ss:StyleID="s49"/>
            </Row>
        </Table>

    </Worksheet>
</Workbook>

A continuación, usamos XSL para convertir esto en el siguiente formato:

<PurchaseOrder xmlns="http://www.rosettanet.org">
   <deliverTo>
      <PhysicalAddress>
         <cityName>Seattle, WA, USA 98111</cityName>
         <addressLine1>Airport Chocolates</addressLine1>
         <addressLine2>2711 Alaskan Way</addressLine2>
         <regionName>USA</regionName>
      </PhysicalAddress>
   </deliverTo>
   <ProductLineItem>
      <ProductQuantity>23</ProductQuantity>
      <productUnit>
         <ProductPackageDescription>
            <ProductIdentification>
               <GlobalProductIdentifier>S3-P7</GlobalProductIdentifier>
            </ProductIdentification>
         </ProductPackageDescription>
      </productUnit>
      <Description>Uncle Bob's Organic Dried Pears</Description>
      <requestedPrice>
         <FinancialAmount>
            <GlobalCurrencyCode>USD</GlobalCurrencyCode>
            <MonetaryAmount>30</MonetaryAmount>
         </FinancialAmount>
      </requestedPrice>
   </ProductLineItem>
   <thisDocumentGenerationDateTime>
      <DateTimeStamp>2001-03-15T00:00:00.000</DateTimeStamp>
   </thisDocumentGenerationDateTime>
</PurchaseOrder>

Nota Esto probablemente no es una solicitud técnicamente completa según la especificación de solicitud de pedido de compra pip 3 A4 pip 3 A4, pero se obtiene la idea.

El truco para hacer que esta transformación sea algo sólida es asignar un nombre a las celdas importantes de las que queremos extraer los datos. Esto se hace con el siguiente estilo de expresión XPath en la transformación XSLT:

 select="/Workbook/Worksheet/Table/Row/Cell[NamedCell[@ss:Name='City']]

Esta expresión concreta busca el Cell objeto que tiene Named el nombre City. El resto de la hoja de estilos es bastante sencillo. Consulte XLToPO.xsl para obtener información adicional.

Pruébelo fuera

Para que esto se ejecute, lo único que debe hacer es instalar MSXML 3.0 y obtener una suspensión de una base de datos Northwind. El código de demostración está conectado a SQL Server de la siguiente manera:

   SQLConnection("server=localhost;uid=sa;pwd=;database=northwind");

Es posible que tenga que cambiar este bit de código si la base de datos Northwind está en otro lugar.

La hoja de cálculo PO.xsl espera que el servicio de catálogo se encuentre en:

https://localhost/catalog/search.aspx

Tendrá que instalar el servicio web search.aspx, search.cs y XLToPO.xsl en un directorio virtual llamado catálogo en la máquina local o cambiar la hoja de cálculo para que apunte a otro lugar.

Para editar la hoja de cálculo, tendrá que desactivar la protección, que se puede realizar mediante el submenú Herramientas/Protección .

Pasos siguientes

Lo ideal sería almacenar los enlaces de servicio de catálogo del proveedor en UDDI. Hay algún código de VBA comentado que lo hará por usted. Busca un serviceInfo de servicio de catálogo reconocido (por serviceKey) y, si lo encuentra, usa el accessPoint contenido en serviceDetails. La API pseudo catalog que utilizo en esta demostración no está registrada como un tipo de servicio conocido en UDDI.

Sería un ejercicio divertido hacer uso de etiquetas inteligentes de Office para hacer cosas similares. Consulte el SDK de etiquetas inteligentes en https://msdn.microsoft.com/office/ para obtener información adicional.