1. Trang chủ
  2. » Công Nghệ Thông Tin

Professional XML Databases phần 6 pot

84 159 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 84
Dung lượng 499,19 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Value DetailsPosition: 93-102 Format: MM/DD/YYYY Description: The order date for invoice N Values: UPS: United States Postal Service; USPS: United Parcel Service; FedEx: Federal Express

Trang 1

First, let's see how to read a delimited file and save the results to an XML document We've alreadyseen examples of the delimited file and XML document that we'll be transforming In this example, thisfile is called ch12_ex1.txt

Kevin Williams,744 Evergreen

Terrace,Springfield,KY,12345,12/01/2000,12/04/2000,1,blue 2 in

grommet,17,0.10,silver 3 in widget,22,0.20,,0,0.00,,0,0.00,,0,0.00

Homer Simpson,742 Evergreen

Terrace,Springfield,KY,12345,12/02/2000,12/05/2000,2,red 1 in

sprocket,13,0.30,blue 2 in grommet,11,0.10,,0,0.00,,0,0.00,,0,0.00

This is mapping into the file ch12_ex1.xml:

Trang 2

First, we need to map from the delimited file to the XML document We've already done this a couple

of pages earlier when we were discussing how transform maps are created

Armed with this information, we can use the following VBScript code to open the flat file, break itapart, and use the DOM to construct the XML equivalent The entire listing can be found in the file,ch12_ex1.vbs, but we'll analyze it here section by section:

Dim fso, ts, sLine

Dim el, dom, root

Dim sField(23)

Dim sThisName, sThisSize, sThisColor

Dim sSize, sColor, sName, sAddress

Dim iLineItem

Dim invoiceBucket, partBucket, customerBucket

Dim li, nl, iCust, iPart, cust, part, sDelimit

iCust = 1

iPart = 1

sDelimit = Chr(44) ' This sets the delimiter to be a comma

We're using the iCust and iPart variables to keep track of our customers and parts that we create, sothat we can generate a unique ID for each element created

Set fso = CreateObject("Scripting.FileSystemObject")

Set dom = CreateObject("Microsoft.XMLDOM")

Set root = dom.createElement("InvoiceData")

dom.appendChild root

We create a FileSystemObject for reading the flat file and writing the XML output, and a DOMobject for building the XML output We also go ahead, create the root element for the DOM output,and add it to the document tree

Set invoiceBucket = dom.createDocumentFragment()

Set partBucket = dom.createDocumentFragment()

Set customerBucket = dom.createDocumentFragment()

Trang 3

This is a common technique when building up an XML document with ordered elements As we parsethe invoices from the flat file, we'll be generating Part and Customer elements, as we need them Theabove variables are going to act as buckets to hold the invoice, part, and customer information in threedifferent places so that they can be output consecutively as we require Sorting them into groups as theflat file is being parsed by using XMLDocumentFragment objects, allows us to easily build the finaloutput for the file – as our output structure requires us to write every Invoice element, then all thePart elements, and then all the Customer elements to the document, in that order.

Set ts = fso.OpenTextFile("invoicedelim.txt")

do while ts.AtEndOfStream <> True

s = ts.ReadLine

for iField = 1 to 22

sField(iField) = left(s, InStr(s, sDelimit) - 1)

s = mid(s, InStr(s, sDelimit) + 1)

next

sField(23) = s

We know we have a comma-delimited file, so we break apart each line into fields based on the

delimiting character we are expecting Naturally, if we can't do this (for example, if there aren't enoughdelimiters in one record – or too many), we would add error handling to report this error to the user Atthis point, the sField() array contains all of the fields found on one record of the flat file

Set el = dom.createElement ("Invoice")

Since each record in our flat file corresponds to one invoice, we can create that Invoice element now

We add it to our Invoice document fragment so that we will be able to write all the invoices out as agroup to the main document at the end of the process

' check to see if we have this customer yet

el.setAttribute "customerIDREF", "NOTFOUND"

Set nl = customerBucket.childNodes

for iNode = 0 to nl.length - 1

sName = nl.item(iNode).getAttribute("name")

sAddress = nl.item(iNode).getAttribute("address")

if sName = sField(1) and sAddress = sField(2) Then

' we presume we have this one already

el.setAttribute "customerIDREF", _

nl.item(iNode).getAttribute("customerID")end if

next

Here, we're examining all the customers in our Customer document fragment to see if we already havethe customer referenced in this invoice Since our XML document normalizes customers together, wewant to reuse a customer that matches the customer on this invoice if possible For the purposes of thisanalysis, we are assuming that a customer with the same name and address is a match If we find amatch for the customer, we simply set the customerIDREF attribute of the invoice to point to it

if el.getAttribute("customerIDREF") = "NOTFOUND" Then

' we need to create a new customer

Set cust = dom.createElement("Customer")

cust.setAttribute "customerID", "CUST" & iCust

cust.setAttribute "name", sField(1)

Trang 4

cust.setAttribute "address", sField(2)

cust.setAttribute "city", sField(3)

cust.setAttribute "state", sField(4)

cust.setAttribute "postalCode", sField(5)

customerBucket.appendChild cust

el.setAttribute "customerIDREF", "CUST" & iCust

iCust = iCust + 1

end if

If we didn't find the customer, we create one and add it to the Customer document fragment, assigning

a new ID to the element We then reference that ID from the customerIDREF attribute of the invoiceelement we are creating

el.setAttribute "orderDate", sField(6)

el.setAttribute "shipDate", sField(7)

if sField(8) = 1 Then el.setAttribute "shipMethod", "USPS"

if sField(8) = 2 Then el.setAttribute "shipMethod", "UPS"

if sField(8) = 3 Then el.setAttribute "shipMethod", "FedEx"

invoiceBucket.appendChild el

We continue to set attributes on the Invoice element, translating the values provided in the flat file totheir appropriate analogues, elements or attributes, depending on what we're using, in our XMLdocument as necessary Once we've done this, we append the element to our Invoice documentfragment

for iLineItem = 1 to 5

if sField(6 + iLineItem * 3) > "" Then

' this line item exists

Here, we iterate through each of the three-field sets that represent a line item We know that if thedescription for the item is present, the line item exists and needs to be represented in our XML target

Set li = dom.createElement ("LineItem")li.setAttribute "quantity", sField(6 + iLineItem * 3 + 1)li.setAttribute "price", sField(6 + iLineItem * 3 + 2)

We create our line item element and set its attributes based on the contents of the flat file

' break apart the description fieldsWork = sField(6 + iLineItem * 3)sThisColor = left(sWork, InStr(sWork, " ") - 1)sWork = Mid(sWork, InStr(sWork, " ") + 1)sThisSize = ""

While InStr(sWork, " ") > 0sThisSize = sThisSize + left(sWork, InStr(sWork, " "))sWork = Mid(sWork, InStr(sWork, " ") + 1)

WendsThisSize = Left(sThisSize, len(sThisSize) - 1)sThisName = sWork

Trang 5

Here, we've decomposed the description of the part provided in the flat file into the name, size, andcolor data points our XML document needs.

Set nl = partBucket.childNodes

li.setAttribute "partIDREF", "NOTFOUND"

for iNode = 0 to nl.length - 1

sName = nl.item(iNode).getAttribute("name")sSize = nl.item(iNode).getAttribute("size")sColor = nl.item(iNode).getAttribute("color")

If sThisName = sName And sThisSize = sSize And sThisColor = sColor _

Then' we presume we have this one alreadyli.setAttribute "partIDREF", _

nl.item(iNode).getAttribute("partID")end if

next

if li.getAttribute("partIDREF") = "NOTFOUND" Then

' we need to create a new partSet part = dom.createElement("Part")part.setAttribute "partID", "PART" & iPartpart.setAttribute "name", sThisNamepart.setAttribute "size", sThisSizepart.setAttribute "color", sThisColorpartBucket.appendChild part

li.setAttribute "partIDREF", "PART" & iPartiPart = iPart + 1

end if

This code is similar to the corresponding code for Customer – we check to see if we have a part in ourpart list yet, and if not, we add it with a new ID For the purposes of parts, we assume that if a partshares the same name, size, and color with a part already created, it is the same part

Once the entire flat file has been processed and we have created all the appropriate elements, we need

to add them back to the document we are creating We can do this by appending the documentfragments for each element type, to the root element of the XML document

Set ts = fso.CreateTextFile("ch12_ex1.xml", True)

ts.Write dom.xml

ts.close

Set ts = Nothing

Trang 6

Finally, we flush the XML to the output file, and we're done.

The output of the preceding script, when run against the sample delimited file we saw earlier, should bethe XML file detailed earlier, with the whitespace absent

Fixed-width

You'll recall the fixed-width example we looked at earlier Below is a similar example but with all of theinformation from the last example included and a more realistic spacing between fields

Kevin Williams 744 Evergreen Terrace Springfield

KY12345 12/01/200012/04/2000UPS blue 2 in grommet

0001700000.10silver 3 in widget 0002200000.20

0000000000.00

Homer Simpson 742 Evergreen Terrace Springfield

KY12345 12/02/200012/05/2000USPS red 1 in sprocket

0001300000.30blue 2 in grommet 0001100000.10

Description: The name of the customer on invoice N

Position: 31-60

Description: The address of the customer on invoice N

Position: 61-80

Description: The city of the customer on invoice N

Position: 81-82

Description: The state of the customer on invoice N

Position: 83-92

Description: The postal code of the customer on invoiceN

Trang 7

Value Details

Position: 93-102

Format: MM/DD/YYYY

Description: The order date for invoice N

Values: UPS: United States Postal Service; USPS:

United Parcel Service; FedEx: Federal Express

Description: The shipping method used to ship the partsordered on invoice N

Position: 118-147

Format: No more than 30 characters

Description: The description of the part ordered in thefirst line item of invoice N, in the form color size name

Trang 8

Format: No more than 30 characters

Description: The description of the part ordered in the third lineitem of invoice N, in the form color size name

record[N].field16 Data type: Numeric

Position: 247-276

Description: The description of the part ordered in the fourthline item of invoice N, in the form color size name

Trang 9

Next, we map the fields back to the XML fields:

record[N].field1 InvoiceData.Invoice[N]->Customer.Name Create a new

customer and linkback to it from theInvoice recordcreated

record[N].field2

InvoiceData.Invoice[N]->Customer.Addressrecord[N].field3 InvoiceData.Invoice[N]->Customer.City

record[N].field4

InvoiceData.Invoice[N]->Customer.Staterecord[N].field5 InvoiceData.Invoice[N]-

>Customer.PostalCode

Table continued on following page

Trang 10

Source Target Comments

Invoice[N].LineItem[1]->Part.Size,InvoiceData

Invoice[N].LineItem[1]->Part.Colorrecord[N].field10 InvoiceData.Invoice[N].LineItem

[1].quantityrecord[N].field11 InvoiceData.Invoice[N].LineItem

[1].pricerecord[N].field12 InvoiceData.Invoice[N].LineItem

[2]->Part.Name,InvoiceData

Invoice[N].LineItem[2]->Part.Size,InvoiceData

Invoice[N].LineItem[2]->Part.Color

Blank (all spaces) if noline 2 appears on theinvoice

record[N].field13 InvoiceData.Invoice[N].LineItem

[2].quantityrecord[N].field14 InvoiceData.Invoice[N].LineItem

[2].pricerecord[N].field15 InvoiceData.Invoice[N].LineItem

[3]->Part.Name,InvoiceData

Invoice[N].LineItem[3]->Part.Size,InvoiceData

Invoice[N].LineItem[3]->Part.Color

Blank (all spaces) if noline 3 appears on theinvoice

record[N].field16 InvoiceData.Invoice[N].LineItem

[3].quantityrecord[N].field17 InvoiceData.Invoice[N].LineItem

[3].pricerecord[N].field18 InvoiceData.Invoice[N].LineItem

[4]->Part.Name,InvoiceData

Invoice[N].LineItem[4]->Part.Size,InvoiceData

Invoice[N].LineItem[4]->Part.Color

Blank (all spaces) if noline 4 appears on theinvoice

Trang 11

Source Target Comments

record[N].field19 InvoiceData.Invoice[N].LineItem[4].quantity

record[N].field20 InvoiceData.Invoice[N].LineItem[4].price

record[N].field21

InvoiceData.Invoice[N].LineItem[5]->Part.Name,InvoiceData Invoice[N].LineItem[5]-

>Part.Size,InvoiceData Invoice[N].LineItem[5]-

>Part.Color

Blank (allspaces) if noline 5appears onthe invoice

record[N].field22 InvoiceData.Invoice[N].LineItem[5].quantity

record[N].field23 InvoiceData.Invoice[N].LineItem[5].price

We can now write the code to perform the transformation This code can be found in the file

ch12_ex2.vbs:

Dim fso, ts, sLine

Dim el, dom, root

Dim sField(23)

Dim sThisName, sThisSize, sThisColor

Dim sSize, sColor, sName, sAddress

Dim iLineItem

Dim invoiceBucket, partBucket, customerBucket

Dim li, nl, iCust, iPart, cust, part

iCust = 1

iPart = 1

Set fso = CreateObject("Scripting.FileSystemObject")

Set dom = CreateObject("Microsoft.XMLDOM")

Set root = dom.createElement("InvoiceData")

dom.appendChild root

Set invoiceBucket = dom.createDocumentFragment()

Set partBucket = dom.createDocumentFragment()

Set customerBucket = dom.createDocumentFragment()

Set ts = fso.OpenTextFile("ch12_ex2.txt")

do while ts.AtEndOfStream <> True

Trang 12

Set el = dom.createElement ("Invoice")

' check to see if we have this customer yet

el.setAttribute "customerIDREF", "NOTFOUND"

Set nl = customerBucket.childNodes

for iNode = 0 to nl.length - 1

sName = nl.item(iNode).getAttribute("name")

sAddress = nl.item(iNode).getAttribute("address")

if sName = sField(1) and sAddress = sField(2) Then

' we presume we have this one alreadyel.setAttribute "customerIDREF", _

nl.item(iNode).getAttribute("customerID")end if

next

if el.getAttribute("customerIDREF") = "NOTFOUND" Then

' we need to create a new customer

Set cust = dom.createElement("Customer")

cust.setAttribute "customerID", "CUST" & iCust

cust.setAttribute "name", sField(1)

cust.setAttribute "address", sField(2)

cust.setAttribute "city", sField(3)

cust.setAttribute "state", sField(4)

cust.setAttribute "postalCode", sField(5)

customerBucket.appendChild cust

el.setAttribute "customerIDREF", "CUST" & iCust

iCust = iCust + 1

end if

el.setAttribute "orderDate", sField(6)

el.setAttribute "shipDate", sField(7)

el.setAttribute "shipMethod", sField(8)

invoiceBucket.appendChild el

for iLineItem = 1 to 5

if trim(sField(6 + iLineItem * 3)) > "" Then

' this line item existsSet li = dom.createElement ("LineItem")li.setAttribute "quantity", sField(6 + iLineItem * 3 + 1)li.setAttribute "price", sField(6 + iLineItem * 3 + 2)' break apart the description field

sWork = sField(6 + iLineItem * 3)sThisColor = left(sWork, InStr(sWork, " ") - 1)sWork = Mid(sWork, InStr(sWork, " ") + 1)sThisSize = ""

While InStr(sWork, " ") > 0sThisSize = sThisSize + left(sWork, InStr(sWork, " "))sWork = Mid(sWork, InStr(sWork, " ") + 1)

WendsThisSize = Left(sThisSize, len(sThisSize) - 1)sThisName = sWork

Set nl = partBucket.childNodesli.setAttribute "partIDREF", "NOTFOUND"

for iNode = 0 to nl.length - 1

Trang 13

sName = nl.item(iNode).getAttribute("name")sSize = nl.item(iNode).getAttribute("size")sColor = nl.item(iNode).getAttribute("color")

If sThisName = sName And sThisSize = sSize And _

sThisColor = sColor Then' we presume we have this one alreadyli.setAttribute "partIDREF", nl.item(iNode).getAttribute("partID")end if

next

if li.getAttribute("partIDREF") = "NOTFOUND" Then

' we need to create a new partSet part = dom.createElement("Part")part.setAttribute "partID", "PART" & iPartpart.setAttribute "name", sThisNamepart.setAttribute "size", sThisSizepart.setAttribute "color", sThisColorpartBucket.appendChild part

li.setAttribute "partIDREF", "PART" & iPartiPart = iPart + 1

Trang 14

Here, we're simply taking the fields from their appropriate location in the source file line The

extraction code could be separated into a separate subroutine that could be changed for different fileformats, while the rest of the code would stay the same for all formats This increases the possibility ofcode reuse, as the extraction process could be pulled out into a separate procedure independent of themapping process

The output of this transformation, when applied to our sample, is the same as for ch12_ex1.xmlabove

Lblue 2 in grommet 0001700000.10

Lsilver 3 in widget 0002200000.20

I12/02/200012/05/2000USPS

CHomer Simpson 742 Evergreen Terrace Springfield

KY12345

Lred 1 in sprocket 0001300000.30

Lblue 2 in grommet 0001100000.10

We need to create a mapping table for this format For the purposes of showing how code may bereused, we'll assume that no more than five parts may appear on one invoice (to make the tagged formatconsistent with the other flat file formats we've examined) The mapping looks like this:

Trang 15

Format: No more than 30 characters

Description: The description of the part ordered in theMth line item of invoice N, in the form color size nameRecord[N].LineItem[M].field2 Data Type: Numeric

Trang 16

Now, we map the fields back to the XML fields:

record[N].Customer.field1 InvoiceData.Invoice[N]->Customer.Name Create a new

customer andlink back to itfrom theInvoice recordcreatedrecord[N].Customer.field2 InvoiceData.Invoice[N]->Customer.Address

record[N].Customer.field3 InvoiceData.Invoice[N]->Customer.City

record[N].Customer.field4 InvoiceData.Invoice[N]->Customer.State

record[N].Customer.field5

InvoiceData.Invoice[N]->Customer.PostalCoderecord[N].Invoice.field1 InvoiceData.Invoice[N].orderDate

>Part.Size,InvoiceData.Invoice[N].LineItem[M]-

>Part.Colorrecord[N].LineItem[M]

.quantityrecord[N].LineItem[M]

We can now write the code to perform the transformation:

Dim fso, ts, sLine

Dim el, dom, root

Dim sField(23)

Dim sThisName, sThisSize, sThisColor

Dim sSize, sColor, sName, sAddress

Dim iLineItem

Dim invoiceBucket, partBucket, customerBucket

Dim li, nl, iCust, iPart, cust, part

Dim bDone

iCust = 1

iPart = 1

Set fso = CreateObject("Scripting.FileSystemObject")

Set dom = CreateObject("Microsoft.XMLDOM")

Set root = dom.createElement("InvoiceData")

dom.appendChild root

Set invoiceBucket = dom.createDocumentFragment()

Set partBucket = dom.createDocumentFragment()

Set customerBucket = dom.createDocumentFragment()

Trang 17

Set ts = fso.OpenTextFile("ch12_ex3.txt")

End If ' This checks to see if we have an empty file so as not to proceed

do while not bDone

If left(sLine, 1) <> "I" Then

Set el = dom.createElement ("Invoice")

el.setAttribute "orderDate", sField(1)

el.setAttribute "shipDate", sField(2)

el.setAttribute "shipMethod", sField(3)

' check to see if we have this customer yet

el.setAttribute "customerIDREF", "NOTFOUND"

Set nl = customerBucket.childNodes

for iNode = 0 to nl.length - 1

sName = nl.item(iNode).getAttribute("name")

sAddress = nl.item(iNode).getAttribute("address")

if sName = sField(1) and sAddress = sField(2) Then

' we presume we have this one already

el.setAttribute "customerIDREF", _

nl.item(iNode).getAttribute("customerID")

end if

next

if el.getAttribute("customerIDREF") = "NOTFOUND" Then

' we need to create a new customer

Set cust = dom.createElement("Customer")

cust.setAttribute "customerID", "CUST" & iCust

cust.setAttribute "name", sField(1)

cust.setAttribute "address", sField(2)

cust.setAttribute "city", sField(3)

cust.setAttribute "state", sField(4)

cust.setAttribute "postalCode", sField(5)

Trang 18

Set li = dom.createElement ("LineItem")

li.setAttribute "quantity", sField(2)

li.setAttribute "price", sField(3)

' break apart the description field

sWork = sField(1)

sThisColor = left(sWork, InStr(sWork, " ") - 1)

sWork = Mid(sWork, InStr(sWork, " ") + 1)

li.setAttribute "partIDREF", "NOTFOUND"

for iNode = 0 to nl.length - 1

sName = nl.item(iNode).getAttribute("name")sSize = nl.item(iNode).getAttribute("size")sColor = nl.item(iNode).getAttribute("color")

If sThisName = sName And sThisSize = sSize And sThisColor = sColor Then' we presume we have this one already

li.setAttribute "partIDREF", nl.item(iNode).getAttribute("partID")end if

next

if li.getAttribute("partIDREF") = "NOTFOUND" Then

' we need to create a new partSet part = dom.createElement("Part")part.setAttribute "partID", "PART" & iPartpart.setAttribute "name", sThisNamepart.setAttribute "size", sThisSizepart.setAttribute "color", sThisColorpartBucket.appendChild part

li.setAttribute "partIDREF", "PART" & iPartiPart = iPart + 1

end if

el.appendChild li

If ts.AtEndOfStream Then

bDone = TruesLine = "DONE"

Trang 19

This code is very similar to code we have already seen The major difference is that elements arecreated as the document is read as necessary – so when an invoice line is read, an Invoice element iscreated; when a customer line is read, a Customer element is created, and so on.

The result of this code when applied to our sample is again the same as the previous XML

Transforming from XML to Flat Files

The other type of transformation, from XML to flat files, calls for a significantly different approach.Let's look at the different programming techniques that may be used to transform an XML document to

a flat file, and then see some examples of our strategy in action

Programming Approaches

Again, there are a couple of different ways you can tackle the conversion of XML to flat files The mostobvious one is to parse the document and serialize it out to a flat file However, another approach thatworks a little better is to use XSLT to transform the XML document into the required output format.Let's look at the advantages and disadvantages of each approach

Parse and Serialize

One strategy would be to parse the XML document, using either SAX or the DOM, and then serializeits contents to a flat file This approach works perfectly well; however, whenever we add a new type offlat file transformation, we need to write more code and potentially recompile it It would be nice if wecould tweak these transforms without requiring significant code modifications

XSLT

It's not widely used this way, yet, but XSLT is actually rather good at producing non-tagged results Itcan be used to generate tab-delimited files, or fixed-width files, or any other sort of result you mightwant to produce The extra benefit is that, to generate a different type of output for an XML document,all you have to do is to add another style sheet We'll be using XSLT for our examples

Handling Different File Types

Let's take a look at an example of each of our different file types, and how we would go about

producing it from our XML document These samples have all been tested using James Clark's XT The

MS Windows executable can be downloaded from: ftp://ftp.jclark.com/pub/xml/xt-win32.zip Thehomepage can be found at: http://www.jclark.com/xml/xt.html

Here is the input XML document we have been, and will continue, using:

Trang 21

Value Details

Record[N].field1 Data type: String

Format: No more than 20 characters

Description: The name of the customer on invoice NRecord[N].field2 Data type: String

Format: No more than 30 characters

Description: The address of the customer on invoice Nrecord[N].field3 Data type: String

Format: No more than 20 characters

Description: The city of the customer on invoice Nrecord[N].field4 Data type: String

Format: Two characters

Description: The state of the customer on invoice Nrecord[N].field5 Data type: String

Format: No more than 10 characters

Description: The postal code of the customer on invoice Nrecord[N].field6 Data type: Datetime

record[N].field9 Data type: String

Format: No more than 30 characters

Description: The description of the part ordered in the first line item

of invoice N, in the form color size namerecord[N].field10 Data type: Numeric

Trang 22

Value Details

record[N].field12 Data type: String

Format: No more than 30 characters

Description: The description of the part ordered in the second lineitem of invoice N, in the form color size name

record[N].field13 Data type: Numeric

Format: #####

Description: The quantity of the part ordered in the second line item

of invoice Nrecord[N].field14 Data type: Numeric

Format: #####.##

Description: The price of the part ordered in the second line item ofinvoice N

record[N].field15 Data type: String

Format: No more than 30 characters

Description: The description of the part ordered in the third line item

of invoice N, in the form color size namerecord[N].field16 Data type: Numeric

record[N].field18 Data type: String

Format: No more than 30 characters

Description: The description of the part ordered in the fourth lineitem of invoice N, in the form color size name

record[N].field19 Data type: Numeric

Trang 23

Value Details

record[N].field21 Data type: String

Format: No more than 30 characters

Description: The description of the part ordered in the fifth line item ofinvoice N, in the form color size name

record[N].field22 Data type: Numeric

Trang 24

Source Target Comments

Trang 25

<xsl:template match="InvoiceData">

Trang 26

InvoiceData is the root element, so the template will be executed once for the entire document.

<xsl:text>&#x09;</xsl:text>

This is how we put in our tab delimiter Notice that we don't need to disable output-escaping, sincewe've already declared that the style sheet should output (unescaped) text &#x09 is the UTF-8 Unicodeidentifier for a tab character

Trang 27

Next, we need to process each LineItem child for the Invoice element Note that we restrict this to fiveelements, as our output format only allows five line items to be written to it.

Trang 28

Here, we write the characters for a carriage return and a line feed to ensure our target file has the hardreturn at the end of the record If the destination delimited file is intended for a UNIX system, you willeither have to change the order of the CR/LF pair being entered, or use a tool like dos2unix, or d2u toconvert the hard return character.

Homer Simpson 742 Evergreen Terrace Springfield KY 12345 12/02/2000

12/05/2000 2 red 1 in sprocket 13 0.30 blue 2 in grommet 11 0.10

0 0.00 0 0.00 0 0.00

Note that we could actually take this one step further, and use the mapping tables we have created inanother document that could be used to drive the transforming document This exercise is left to thereader

Fixed-width

Fixed-width files can be created in a similar fashion using XSLT There are a couple of new tricks thatmay be used to ensure that fields are the proper width – we'll see how these are done when we examinethe code Remember that the map for our fixed-width sample file looks like this:

Trang 29

Value Details

record[N].field5 Data type: String

Position: 83-92

Description: The postal code of the customer on invoice N

record[N].field6 Data type: Datetime

Format: No more than 30 characters

Description: The description of the part ordered in the first line item

of invoice N, in the form color size namerecord[N].field10 Data type: Numeric

Trang 30

Format: No more than 30 characters

Description: The description of the part ordered in the third lineitem of invoice N, in the form color size name

record[N].field16 Data type: Numeric

Position: 234-238

Format: #####

Description: The quantity of the part ordered in the third line item

of invoice Nrecord[N].field17 Data type: Numeric

Trang 31

Description: The description of the part ordered in the fifth line item

of invoice N, in the form color size namerecord[N].field22 Data type: Numeric

Trang 32

Source Target Comments

on theinvoice.InvoiceData.Invoice[N].LineItem[2].quantity record[N].field13

on theinvoice.InvoiceData.Invoice[N].LineItem[3].quantity record[N].field16

on theinvoice.InvoiceData.Invoice[N].LineItem[4].quantity record[N].field19

on theinvoice.InvoiceData.Invoice[N].LineItem[5].quantity record[N].field22

InvoiceData.Invoice[N].LineItem[5].price record[N].field23

Trang 33

The style sheet that performs the translation is shown below and can be found in the code zipfile for thisbook as ch12_ex5.xsl:

Trang 34

Since the order in which fields appear in the fixed-width file is almost the same as the order in whichthey appear in the delimited file, this style sheet is very similar to the previous one We do introduceone new technique in this style sheet that bears examination though:

xsl:value-of select="substring(concat(@orderDate, ' '), 1, 10)" />

The substring-concat pair is the easiest way to get a string of a particular length in XSLT Theabove select string will always return a string that is exactly ten characters long – if the attribute is morethan ten characters, only the first ten will be returned; if the attribute is less than ten characters, it will

be right-padded with spaces

The output of the style sheet above, when applied to our sample XML, is this, the file we started with inthe earlier section:

Kevin Williams 744 Evergreen Terrace Springfield

KY12345 12/01/200012/04/2000UPS blue 2 in grommet

0001700000.10silver 3 in widget 0002200000.20

0000000000.00

Homer Simpson 742 Evergreen Terrace Springfield

KY12345 12/02/200012/05/2000USPS red 1 in sprocket

0001300000.30blue 2 in grommet 0001100000.10

Trang 35

Format: No more than 30 characters

Description: The description of the part ordered in theMth line item of invoice N, in the form color sizename

record[N].LineItem[M].field2 Data Type: Numeric

Trang 36

We need to map from the XML fields to the target file fields, as shown below:

InvoiceData.Invoice[N]->Customer.Name record[N].Customer.field1InvoiceData.Invoice[N]->Customer.Address record[N].Customer.field2InvoiceData.Invoice[N]->Customer.City record[N].Customer.field3InvoiceData.Invoice[N]->Customer.State record[N].Customer.field4InvoiceData.Invoice[N]-

>Customer.PostalCode

record[N].Customer.field5InvoiceData.Invoice[N].orderDate record[N].Invoice.field1InvoiceData.Invoice[N].shipDate record[N].Invoice.field2InvoiceData.Invoice[N].shipMethod record[N].Invoice.field3InvoiceData.Invoice[N].LineItem[M]-

<xsl:value-of select="substring(concat(

/Customer[@customerID=$customerID]/@address,' '), 1, 30)" />

<xsl:value-of select="substring(concat(

/Customer[@customerID=$customerID]/@city,' '), 1, 20)" />

<xsl:value-of select=" /Customer[@customerID=$customerID]/@state" />

<xsl:value-of select="substring(concat(

/Customer[@customerID=$customerID]/@postalCode,' '), 1, 10)" />

Trang 37

The output of the style sheet when applied to the sample XML is this:

I12/01/200012/04/2000UPS

CKevin Williams 744 Evergreen Terrace Springfield

KY12345

Lblue 2 in grommet 0001700000.10

Lsilver 3 in widget 0002200000.20

I12/02/200012/05/2000USPS

CHomer Simpson 742 Evergreen Terrace Springfield

KY12345

Lred 1 in sprocket 0001300000.30

Lblue 2 in grommet 0001100000.10

Summary

In this chapter, we've learned some techniques for working with flat files and moving data between flatfiles and XML We've seen that, to create a translator between the two, you should follow these steps:

6 Map the source format to name-value pairs

6 Map the target format to name-value pairs

6 Correlate the source and target name-value pairs

6 Write DOM code (for XML targets) or an XSLT stylesheet (for flat file targets)

Using this strategy will allow you to connect your systems to legacy systems or other platforms thatproduce or consume flat files, resulting in less programming overhead

Trang 39

Active Data Objects (ADO) first supported XML in version 2.1 with the ability to persist Recordsetobjects to and from XML to the file system The subsequent release of ADO 2.5 expanded on its XMLfeatures by introducing support for loading XML to and from the Stream object (a stream of text orbinary bytes) Now, with the release of ADO 2.6 and SQL Server 2000, we have a lot more power.ADO 2.6 allows us to retrieve XML results in streams instead of recordsets This allows us to retrieveXML data from any OLE DB data source that can send XML.

We'll see a lot of the functionality that SQL Server 2000 exposes in Chapters 14 and 15 Essentially,

we can use the FOR XML extensions to SQL, Open XML, and XML Views via ADO, to offer similarfunctionality through ADO This works with any data source that will return XML, not just SQLServer 2000

ADO can run queries via XML, join XML datasets to relational data, and even stream XML in and out

of stored procedures and ASP pages

It's beyond the scope of this chapter to teach you ADO, so if you're not familiar with ADO, or you

just want to know more, we'd recommend you get hold of a copy of ADO 2.6 Programmer's

Reference, ISBN 1-861004-63-x, from Wrox Press.

In this chapter, we will discuss the following topics:

❑ How ADO has progressed to include a more robust XML feature set than in the past Here wewill discuss what's supported in ADO 2.6, and its new XML properties

❑ Different ways in which we can persist XML via ADO, and how the Stream makes some ofthis possible, including a look at the ASP Response object

❑ How we can query SQL Server and return XML data, both using extensions to the SQLlanguage, and querying using XPath and mapping schemas

❑ How we can merge XML data sets with SQL data sets to retrieve and even modify SQL data

Trang 40

Wéll also take a sneak preview look at what's coming in the future, by investigating ADỢ

As you can see already, we have a full agenda up ahead So grab a comfy chair and kick back as we diveright in to explore ADO and XML

The code in this chapter relies on ADO 2.6 and SQL Server 2000 The XML in this

chapter is displayed in the Internet Explorer 5 browser While other browsers may

not display the data in the same way, it is important to keep in mind that the same

XML can be passed to any client; whether or not that client can display the data

depends entirely on the client.

XML Support in ADO 2.6 and SQL Server 2000

Wéll start out by discussing the features of ADO 2.6 that facilitate the integration between ADO andXML:

❑ The Stream object

❑ The ability to persist data as XML

❑ Running queries against data in XML

❑ Annotated schemas that allow us to map an XML vocabulary to SQL Server tables

❑ Merging XML with relational data

The topics in this section will introduce you to the concepts and techniques, while the remainingsections of this chapter will concentrate on showing you how to tackle XML integration with ADO andSQL Server 2000 with plenty of code examples First, however, wéll tackle what a stream is, and whatits role is with respect to ADO and XML Then wéll discuss, at a high level, the different ways in which

we can use the stream and the other XML based features of ADO and SQL Server 2000

What is a Stream?

The ADO Stream object provides the means to read, write, and manage the binary (or text) stream ofbytes that make up a file or messagẹ In particular, we can use a Stream object to read a file, write to afile, or read or write data to or from a binary stream (temporary memory) We can also send the

Stream over a network from a business object to a client So what can the Stream object do for yoủ

❑ We can use a Stream as a means to save or persist datạ For example we can take a

Recordset and save it in the XML format to a Stream object Once the XML is in theStream, we can then save it to a string variable, or even load it into the XML DOM

❑ If you remember that the ASP Response object supports an interface for the stream, you willsee that we can send XML directly to the Response object, thus writing it to a client's

Ngày đăng: 13/08/2014, 12:21

TỪ KHÓA LIÊN QUAN