XML Web Service-Enabled Office 문서

 

크리스 러벳
Microsoft Corporation

2001년 3월 19일

Xml03192001.exe다운로드합니다.

Microsoft Office XP 및 .NET Web Services의 결혼 준비가 되셨나요? 네트워크로 연결된 B2B 전자 상거래 환경에서는 비즈니스 프로세스 워크플로를 사람들이 데스크톱에서 수행하는 모든 것에 통합하여 최종 사용자에게 Web Services의 강력한 성능을 제공하는 것은 어떨까요? 나는 무엇에 대해 얘기하고 있는가? 그림 1과 비슷한 Excel 스프레드시트입니다.

그림 1. Web Services 지원 Excel 스프레드시트

이것은 단지 일반적인 스프레드시트가 아닙니다. UDDI를 사용하여 회사 주소를 찾고 카탈로그 웹 서비스를 사용하여 제품 정보를 찾습니다. 또한 XML 스프레드시트 형식에서 XML 변환을 수행하여 보내기 단추를 클릭할 때 RosettaNet PIP 3 A4 구매 주문 요청 형식을 생성합니다.

구매 중인 회사의 이름을 입력한 다음 찾기 단추를 클릭하면 스프레드시트 뒤에 있는 일부 VBA 코드가 UDDI 호출을 수행하고 나머지 주소 섹션을 채웁니다. 예를 들어 Microsoft를 입력하고 찾기를 클릭하면 구매 대상 필드에 다음이 표시됩니다.

그림 2. 구매 후 필드

23의 수량을 입력한 다음 설명 필드에 Pear라는 용어를 입력한 다음 TAB 키를 누르면 일부 VBA 코드는 SOAP 카탈로그 웹 서비스를 쿼리하여 일치하는 제품을 찾을 수 있는지 확인하고 세부 정보를 채웁니다. 이 경우 카탈로그 웹 서비스를 Northwind 데이터베이스에 유선으로 연결했으므로 다음을 반환합니다.

그림 3. 스프레드시트의 주문 부분을 자세히 살펴보기

이 경우 설명을 작성하고 해당 제품에 대한 모든 것을 알려주는 HTML 페이지로 연결되는 링크로 전환했습니다.

둘 이상의 제품을 찾을 수 있고 입력한 제품과 정확히 일치하는 제품이 없는 경우 선택 항목의 드롭다운 목록이 제공됩니다. 예를 들어 두부를 입력하면 다음과 같은 선택 항목이 표시됩니다.

그림 4. 정확한 일치 항목을 찾을 수 없는 경우 제공되는 여러 선택 항목의 예

이러한 선택 항목 중 하나를 선택하면 특정 세부 정보가 제공됩니다.

완료되면 보내기 단추를 클릭하면 RosettaNet PIP 3 A4 XML 구매 주문 형식이 생성되고 주문이 전송됩니다.

이 모든 것이 어떻게 작동하나요?

도구 메뉴로 이동하여 스프레드시트 뒤의 VBA 코드를 찾아서 매크로, Visual Basic Editor를 차례로 선택할 수 있습니다. 스프레드시트의 변경 내용에 반응하는 ThisWorkbook 뒤에는 약간의 코드가 있습니다. 특히 Workbook_SheetChange 이벤트는 설명을 삭제할 때 줄 항목을 지우고 Workbook_SheetSelectionChange 이벤트는 설명 필드에서 SKU 필드로 탭할 때 FindProduct()를 호출합니다. FindProductXMLNode를 반환하는 경우 관련 필드가 해당 노드에서 끌어와 나머지 줄 항목 세부 정보를 채웁니다.

UDDI find_business 호출의 작동 방식은 이전 문서 UDDI: XML 웹 서비스에서 찾을 수 있습니다. 비즈니스가 발견되면 UDDI 응답의 /businessInfo/contacts/contact/address/ 부분에 있는 addressLines 를 사용하여 구매처 주소 블록을 채웁니다.

카탈로그 웹 서비스

카탈로그 모듈의 FindProduct 함수는 조회할 검색어를 포함하는 URL 매개 변수를 사용하여 카탈로그 서비스 URL을 호출합니다. SOAP 응답을 다시 가져와서 /Envelope/Body/Fault와 일치하는지 먼저 확인합니다. 오류가 아닌 경우 CatalogQueryResult> 검사를 열어 <반환된 항목의 ProductName 특성이 지정된 용어와 일치하는지 확인합니다. 또한 표시되는 영역 외부의 페이지 아래로 선택 항목의 드롭다운 목록을 빌드합니다. 데이터 메뉴로 이동하고 유효성 검사를 선택하여 드롭다운 목록의 작동 방식을 확인할 수 있습니다.

카탈로그 웹 서비스는 매우 간단합니다. .aspx 진입점은 search.cs에 정의된 CatalogSearch 개체를 만들고 Execute를 호출하여 다음과 같이 HttpResponse 출력 스트림을 전달합니다.

<%@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/>");
   }
%>

Execute 메서드는 재미가 시작되는 곳입니다. SQL SELECT 문에서 특정 필드를 반환하는 XmlTextWriter에 래핑된 매우 간단한 SQL 관리되는 공급자 코드입니다. 따라서 기본적으로 DataReader를 통해 다음과 같이 XmlTextWriter에 쓰는 동안 반복됩니다.

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();
}

URL https://localhost/catalog/search.aspx?term=tofu 은 다음 결과를 반환합니다.

<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>

이는 .NET 프레임워크를 사용하여 SQL Server XML을 가져올 수 있는 가장 효율적인 방법에 관한 것입니다. 매우 대략적인 측정을 통해 Dell PowerEdge 2400에서 초당 약 80~90을 얻었습니다.

보내기 단추

SendOrder() 함수는 스프레드시트에서 선택한 셀 범위의 XML 표현에서 XML 문서를 로드합니다. 이 작업은 다음과 같은 VBA 코드의 매직 라인으로 수행됩니다.

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

이렇게 하면 스프레드시트의 해당 셀 범위에 대한 모든 것을 완전히 설명하는 거대한 XML 청크가 반환됩니다. 다음은 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>

그런 다음 XSL을 사용하여 이를 다음 형식으로 바꿉니다.

<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>

참고 이것은 아마도 RosettaNet PIP 3 A4 구매 주문 요청 사양에 따라 기술적으로 완전한 요청이 아니지만 아이디어를 얻을 수 있습니다.

이 변환을 다소 강력하게 만드는 비결은 데이터를 끌어오려는 중요한 셀의 이름을 지정하는 것입니다. 이 작업은 XSLT 변환에서 다음과 같은 XPath 식 스타일로 수행됩니다.

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

이 특정 식은 Named 이름이 CityCell 를 찾습니다. 스타일시트의 나머지 는 꽤 똑바로 앞으로. 자세한 내용은 XLToPO.xsl을 참조하세요.

사용해 보기

이 작업을 실행하려면 MSXML 3.0을 설치하고 Northwind 데이터베이스를 보류하기만 하면 됩니다. 데모 코드는 다음과 같이 SQL Server 연결됩니다.

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

Northwind 데이터베이스가 다른 곳에 있는 경우 이 코드 비트를 변경해야 할 수 있습니다.

PO.xsl 스프레드시트에는 카탈로그 서비스가 다음 위치에 있을 것으로 예상됩니다.

https://localhost/catalog/search.aspx

로컬 컴퓨터의 카탈로그 라는 가상 디렉터리에 Web Service search.aspx, search.cs 및 XLToPO.xsl을 설치하거나 스프레드시트를 다른 곳을 가리키도록 변경해야 합니다.

스프레드시트를 편집하려면 도구/보호 하위 메뉴로 수행할 수 있는 보호를 해제해야 합니다.

다음 단계

이상적으로는 공급업체의 카탈로그 서비스 바인딩을 UDDI에 저장하려고 합니다. 이 작업을 수행하는 몇 가지 VBA 코드가 주석 처리되어 있습니다. 인식된 Catalog Service serviceInfo(serviceKey별)를 찾은 다음, 이를 찾으면 serviceDetails 내에 포함된 accessPoint를 사용합니다. 이 데모에서 사용 중인 의사 카탈로그 API는 UDDI에서 알려진 서비스 유형으로 등록되지 않았습니다.

Office 스마트 태그를 사용하여 비슷한 작업을 수행하는 것이 재미있는 연습이 될 것입니다. 자세한 내용은 스마트 태그 SDK 켜 https://msdn.microsoft.com/office/ 기를 참조하세요.