Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 84 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
84
Dung lượng
0,95 MB
Nội dung
XML Views in SQL Server 2000 611 XPath oddities like this compel us to recommend against the use of long paths like A/B in predicates. Most likely, the meaning you wanted is actually a nested predicate like /Order[Product[@UnitPrice > 10]] anyway. Because SQL XML does not support positional predicates, it uses "any" semantics for both of these XPaths. That is, both /Order[0 + Product/@UnitPrice > 10] and /Order[Product/@UnitPrice > 10] produce the same XML result in SQL XML. This deviation from the W3C standard also applies to relational and equality operators. These operators apply special conversion rules to their operands that we will not explain in detail here. For example, an expression @Date > '1998-10-01' should first convert both the nodeset @Date and the string '1998-10-01' to number (which will result in NaN), and then compare them (which will result in false, since NaN compared with anything is false). SQL XML instead performs a string comparison, with the expected result (true if and only if the value of @Date is a date later than the one indicated in the string). Here's an XPath that attempts string and date comparisons. These would not work in ordinary XML documents, but do work in SQL XML: /Customer[@CustomerID > 'PARIS']/Order[@OrderDate <= '1999-01-01'] which results in the XML <Order OrderID="10322" OrderDate="1996-10-04"> <Product ProductID="P52" UnitPrice="7.0000" Units="38"/> </Order> <Order OrderID="10354" OrderDate="1996-11-14"> <Product ProductID="P1" UnitPrice="18.0000" Units="39"/> <Product ProductID="P29" UnitPrice="123.7900" Units="0"/> </Order> <Order OrderID="10474" OrderDate="1997-03-13"> <Product ProductID="P14" UnitPrice="23.2500" Units="35"/> <Product ProductID="P28" UnitPrice="45.6000" Units="26"/> <Product ProductID="P40" UnitPrice="18.4000" Units="123"/> <Product ProductID="P75" UnitPrice="7.7500" Units="125"/> </Order> <! > At the time of this writing, none of the XPath string functions (concat(), substring(), etc.) are supported. Microsoft has announced intentions to support these functions in the near future. XPath and the XML View XPath works by translating the XPath into an equivalent FOR XML EXPLICIT query. During this translation process, XPath makes use of the many annotations provided in the XML View. XPath applies join relationships when navigating from one node to another. If the nodes are joined in the schema, then the join relationship will be used in the SQL query. Predicates correspond to existence tests (WHERE EXISTS). Chapter 15 612 Nodes that have an id-prefix are converted to string, and then the prefix is prepended to the value. Note that this prevents using those values as numbers in the XPath. For example, /Product[@ProductID=11] is an error; the correct XPath uses the id prefix: /Product[@ProductID='P11']. In many cases, key information is required to correctly order and nest the resulting XML. If an XPath query seems to be returning odd results, or returns a FOR XML EXPLICIT error, the problem may be that the schema is missing sql:key-fields. Read the section about this annotation for instructions on its use. Finally, XPath queries must perform many data conversions. XPath translates first from the SQL type to the XDR type, and then from the XDR type to the XPath type. This means that specifying XDR and SQL types in the schema can help eliminate unnecessary conversions. When the query converts a column used as an index (for example, /Customer[@CustomerID='ALFKI']), eliminating the unnecessary conversion can result in a ten-fold performance improvement of the XPath query. Default Schema XPath works best with an XML View, but can work without any schema at all – with some restrictions. These restrictions (names, flat hierarchy) are the same restrictions as on the default mapping used by an XML View. (See the earlier section, "The Default Mapping," for details.) In addition, an XPath with no XML View must select the value of a single column from a single row. Because there is no schema to describe how the XML should be shaped, the XPath cannot return XML. The default schema can be especially convenient for so called "direct object" queries that use an XPath- like syntax to access objects in the database. For example, the XPath /Customers[@CustomerID='ALFKI']/@ContactName is exactly the same as the SQL query SELECT ContactName FROM Customers WHERE CustomerID='ALFKI' XPath Parameters XPath parameters are prefixed with the dollar-sign symbol (for example, $param). SQL XML supports only string-valued parameters, but this presents no great difficulties. Parameters can be shared among other queries in a template. For example, the following template selects the Customer element with the id parameter value that was passed to the template (which defaults to "ALFKI"): <xpath-params xmlns:sql="urn:schemas-microsoft-com:xml-sql"> <sql:header> <sql:param name="id">ALFKI</sql:param> </sql:header> <sql:xpath-query mapping-schema="xpath.xdr"> /Customer[@CustomerID=$id] </sql:xpath-query> </xpath-params> XML Views in SQL Server 2000 613 Additional XPath Axes XPath is not limited to top-down navigation (from an element to its children and attributes). XPath has a rich set of navigation axes, including namespaces, descendants, ancestors, and so on. However, at the time of this writing, SQL XML supports only four axes: child, attribute, parent, and self. In particular, the popular descendant-or-self shortcut "//" is not supported. All four of these have abbreviated forms that are more commonly used. For the child and attribute axes, we've seen that the abbreviations have the form child or @attribute, respectively. For parent, the short form is two dots ( ) and one dot (.) is the short form for self. Thus, the XPath /Customer/Order[ /@CustomerID='ALFKI'] is equivalent to the XPath /Customer[@CustomerID='ALFKI']/Order All of these also have longer forms that look like axisname::nodetest. So the previous XPath could also be written /child::Customer[attribute::CustomerID='ALFKI']/child::Order In this case, the node test is just the name of the element or attribute. Other node tests include functions like node() (selects all nodes) and text() (selects all text nodes) and the wildcard * (which is similar to node(), but not exactly the same). At the time of this writing, SQL XML supports only names and node(). The abbreviation is short for parent::node() and the abbreviation . is short for self::node(). So the XPath above that uses could also be rewritten as: /child::Customer/child::Order[parent::node()/attribute::CustomerID='ALFKI'] Updategrams At this time, there is no W3C standard for updating XML documents. Updategrams attempt to fill this void by specifying a standard XML-based language for inserting, updating, and deleting XML data. Updategrams are declarative. You describe what the XML currently is and what you want it to become, and the updategram takes care of all the details necessary to make it so. Updategrams use the namespace URI urn:schemas-microsoft-com:xml-updategram, which we will always assign to the prefix u. In SQL Server 2000, updategram queries are executed through templates. Each updategram uses an XML View of the database to determine the SQL query that is required to perform the update. NOTE: Updategrams require the latest SQL XML web release from MSDN, or SQL Server 2000 SP1 or later. The examples in this section are not compatible with the early beta version of updategrams that was released for SQL Server 2000 beta 2. Chapter 15 614 Introduction Every updategram consists of one <u:sync> element, corresponding to one database transaction. The transaction is described by a sequence of <u:before> and <u:after> pairs. Every <before> must have a matching <after>, and vice-versa; if one is missing, then it is equivalent to one with empty content. The contents of the <before> element are compared with the contents of its matching <after> element to determine whether an INSERT, UPDATE, or DELETE is required. To avoid conflicts between multiple, concurrent queries, updategrams employ "optimistic concurrency control". If the current state of the database does not match the XML described in the <before> element, then the transaction will not be committed, and no change will be made. Depending on how specific the <before> element is, the synchronization will effectively range from none at all ("update always") to total synchronization ("update only if the row has not changed at all"). To demonstrate updategrams, let's create a table: CREATE TABLE FictionalCharacters (cid nvarchar(10) PRIMARY KEY, FirstName nvarchar(40), LastName nvarchar(40)) We now use the following schema, ch15_ex21.xdr, for mapping the table: <Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes" xmlns:sql="urn:schemas-microsoft-com:xml-sql"> <ElementType name="First" content="textOnly" /> <ElementType name="Last" content="textOnly" /> <ElementType name="Person" sql:relation="FictionalCharacters" sql:key-fields="cid"> <AttributeType name="ID" dt:type="id"/> <attribute type="ID" sql:field="cid"/> <element type="First" sql:field="FirstName"/> <element type="Last" sql:field="LastName"/> </ElementType> </Schema> This template (ch15_ex22.xml) demonstrates an insert into the FictionalCharacters table: <insert> <u:sync mapping-schema="ch15_ex21.xdr" xmlns:u="urn:schemas-microsoft-com:xml-updategram"> <u:before/> <u:after> <Person ID="HGTTG42"> <First>Arthur</First> <Last>Dent</Last> </Person> </u:after> </u:sync> <sql:xpath-query mapping-schema="ch15_ex21.xdr" xmlns:sql="urn:schemas-microsoft-com:xml-sql"> Person </sql:xpath-query> </insert> XML Views in SQL Server 2000 615 The result of executing this template, if the updategram succeeds, will be <insert> <Person ID="HGTTG42"> <First>Arthur</First> <Last>Dent</Last> </Person> </insert> or <insert> <?MSSQLError Some Error Message Here ?> </insert> if it fails. When successful, the updategram inserts a new row in the FictionalCharacters table with the cid, FirstName, and LastName column values from the XML. Had there been other columns in that row, they would have been set to NULL since their values were not specified. We can now update this row, using this updategram (ch15_ex22a.xml): <update> <u:sync mapping-schema="ch15_ex21.xdr" xmlns:u="urn:schemas-microsoft-com:xml-updategram"> <u:before> <Person ID="HGTTG42"> <First>Arthur</First> </Person> </u:before> <u:after> <Person ID="HGTTG42"/> </u:after> </u:sync> <sql:xpath-query mapping-schema="ch15_ex21.xdr" xmlns:sql="urn:schemas-microsoft-com:xml-sql"> Person </sql:xpath-query> </update> The result of this template (when successful) will be: <update> <Person ID="HGTTG42"> <Last>Dent</Last> </Person> </update> because the FirstName value specified in the <before> element is removed (that is, set to NULL) in the <after> element. In the first template, the <before> element was empty, so the updategram became an INSERT. In the second, the contents of the <before> and <after> elements were matched and the updategram became an UPDATE. However, had the elements matched differently, it could have been a DELETE and an INSERT instead. Before we examine the heuristics used to determine what kind of query an updategram represents, let us first consider how an updategram handles the values given it, especially NULL. Chapter 15 616 Values, Absence and NULL Up until now, we've said that absence of XML data is equivalent to a SQL NULL value, and vice-versa. Unfortunately, this equivalence presents a problem for an updategram, because optimistic concurrency control applies only to the values in the before element. If the value was NULL, it would be absent, and thus would not figure into the equation (even though we might not want to perform the update or delete if the value has changed away from NULL). Therefore, updategrams need a way to explicitly differentiate NULL values from absent ones. Updategrams allow the user to specify a string value that will be used in the XML in place of a SQL NULL. Whenever an XML value is equal to this string, the string is replaced with NULL in the equivalent SQL query. The string is specified with the attribute u:nullvalue on the <u:sync> element or <u:header> element. A popular value to use for u:nullvalue is the string NULL itself. After having executed the previous templates, let's perform another one that restores the first name of our fictional character (ch15_ex23.xml): <restore> <u:sync mapping-schema="ch15_ex21.xdr" xmlns:u="urn:schemas-microsoft-com:xml-updategram" u:nullvalue="NULL" > <u:before> <Person ID="HGTTG42"> <First>NULL</First> </Person> </u:before> <u:after> <Person ID="HGTTG42"> <First>Arthur</First> </Person> </u:after> </u:sync> </restore> This updategram will commit only if the FirstName is still NULL. Note that when evaluating the value of an element, updategrams don't use the usual definition of string value. In XPath syntax, string(element) usually takes all the text node descendants of the element and concatenates them together in document order, which is equivalent to the XPath string(element//text()). Updategrams use only the text nodes that are immediate children of the element, equivalent to the XPath string(element/text()). When the string value of the element matches the u:nullvalue, NULL is substituted in its place. Also, updategrams are aware of XDR default. That is, when an element or attribute value is absent, updategrams use the default value (if given) in the annotated XDR schema. The default is indicated in the schema on an <AttributeType> or <ElementType> using the default attribute. When there is no default value, no value is used for the absent element or attribute. XML Views in SQL Server 2000 617 Insert/Update/Delete Heuristics Now that you understand how an updategram extracts the XML values out of the before and after elements and how it handles absence and default values, the only remaining piece of the puzzle is determining which values in the after element correspond to which values in the before element. Once this matching has been performed, the updategram knows which rows to update, which to delete, and which to insert, and can create the corresponding SQL query to perform that work. An updategram matches elements based on an element key. This key can be specified in the annotated schema using sql:key-fields, or it can be specified in the updategram using the u:id annotation. If the u:id method is chosen, then it must be used everywhere in the updategram. As an example, consider the following updategram (ch15_ex24.xml): <keys> <u:sync xmlns:u="urn:schemas-microsoft-com:xml-updategram" mapping-schema="ch15_ex21.xdr"> <u:before> <Person ID="HGTTG42"> <First>Arthur</First> <Last>Dent</Last> </Person> </u:before> <u:after> <Person ID="HGTTG42"> <First>Ford</First> <Last>Prefect</Last> </Person> <Person ID="HGTTG54"> <First>Arthur</First> <Last>Dent</Last> </Person> </u:after> </u:sync> </keys> Because EmployeeID is known from the schema to be a key, and it uniquely identifies the Employee elements, this updategram will match the two Person elements with ID HGTTG42, and find no match for Person HGTTG54 in the <before> image. There are no default or nullvalue attributes to apply. Therefore, the updategram will perform one UPDATE for HGTTG42, and one INSERT for HGTTG54. As a second example, consider the updategram (ch15_ex25.xml) <u:sync xmlns:u="urn:schemas-microsoft-com:xml-updategram" mapping-schema="ch15_ex21.xdr"> <u:before> <Person u:id="forty-two" ID="HGTTG42"/> <Person u:id="fifty-four" ID="HGTTG54"/> </u:before> <u:after> <Person u:id="fifty-four" ID="54"/> <Person u:id="forty-two" ID="42"/> </u:after> </u:sync> Chapter 15 618 This updategram needs to change the value of the key itself. The only way to do this is to identify the elements using u:id. The values used for u:id are arbitrary; they are used only for matching elements in the updategram, and will not be inserted into the database: as a result, this updategram will not work. Of course, u:id is not limited to key changes; it can be used any time. Parameters Updategrams use parameters exactly like XPath does, and with a similar syntax. Anywhere an updategram contains the dollar-sign ($) followed by the name of a parameter, the parameter value will be substituted. As an example, consider the updategram (ch15_ex26.xml) <parameterized-insert xmlns:u="urn:schemas-microsoft-com:xml-updategram"> <u:header u:nullvalue="NULL"> <u:param name="first">Bob</u:param> <u:param name="last">Doe</u:param> <u:param name="id"/> </u:header> <u:sync mapping-schema="ch15_ex21.xdr" u:nullvalue="NULL"> <u:before/> <u:after> <Person ID="$id"> <First>$first</First> <Last>$last</Last> </Person> </u:after> </u:sync> </parameterized-insert> This updategram will insert a new fictional character using the parameters passed in to the template, or the default values "Bob" and "Doe", if the parameters are not passed to the template (since these are the default parameter values given in the template header). Default Schema We previously described the subset of XPath that can be executed without a schema. Updategrams can also use a default mapping, with some restrictions. These restrictions (names, flat hierarchy) are similar to the default mapping used by an XML View (See the earlier section, "The Default Mapping," for details). In addition, updategrams cannot work with any of the SQL types binary, image, ntext, text, or varbinary in the <before> element and binary, image, or varbinary in the <after> element. Values that map to monetary SQL types (money and smallmoney) must be preceded with a currency symbol such as $; conversely, values preceded with a currency symbol cannot be inserted, updated, or deleted from any string type column in the database (char, nvarchar, etc.). XML Views in SQL Server 2000 619 Server-Generated Identities Automatically-generated column values (such as identity columns) can be indicated in an updategram using the u:at-identity attribute. For example: <auto-identity> <u:sync xmlns:u="urn:schemas-microsoft-com:xml-updategram"> <u:after> <Employees u:at-identity="x" FirstName="Jack" LastName="Ryan"/> </u:after> </u:sync> </auto-identity> will insert a new record into the Employees table, which has an auto-identity column (EmployeeID). The symbol used to represent the identity (in this example, x) can be referred to in sub-elements; wherever the symbol occurs as a value, it will be replaced with the identity that was generated from the insert. Also, the generated value can be returned as part of the template result by using the u:returnid attribute on the u:after element. For example, the template <return> <u:sync xmlns:u="urn:schemas-microsoft-com:xml-updategram"> <u:after u:returnid> <Employees u:at-identity="x" FirstName="Jack" LastName="Ryan"/> </u:after> </u:sync> </return> produces a result like: <return> <returnid> <x>10</x> </returnid> </return> Multiple auto-generated columns can be returned by specifying them as a space-separated list in the u:returnid value. Unfortunately, auto-generated values are not integrated with parameters, so it is not possible to refer to them in other queries in the same template. However, one could use u:returnid to pass the values created in one updategram to another template. Data Types All values that map to any of the SQL types binary, image, ntext, text, or varbinary must be marked in the schema as having that sql:datatype. Otherwise, the updategram will not be able to generate a valid SQL query. Similarly, both monetary types (money, smallmoney) must be marked as having one of the XDR numeric types to be properly used, even though you could still have an attribute type unitprice, without either datatype. The XDR binary types bin.hex and bin.base64 are used when decoding binary values. Binary values cannot be referred to using a dbobject URL (as generated by sql:url-encode). If an attribute or element has a sql:id-prefix in the schema, then that prefix will be stripped out of the value in the updategram. Chapter 15 620 Overflow When an element is marked as having an sql:overflow-field in the schema, any data in the u:after element that is not otherwise consumed will be placed into the overflow column. (The overflow column must be one of the SQL string types, and should have enough space to store the value.) This includes elements or attributes that were marked as sql:map-field="0" but appeared in the updategram. Advanced Topics Namespaces and External Schemas Most uses of XML require namespaces, whether some externally defined namespace or your own custom one. There are two central concepts required when using namespaces in XML Views: namespace declarations and the sql:target-namespace annotation. Recall that namespace declarations come in two forms, xmlns="uri" and xmlns:prefix="uri", and are inherited of the descendants of the element where they were declared. Namespace URIs are commonly overloaded for many different purposes – versioning (like the XSL namespaces) and actual URLs (that you can visit on the Web) are just two examples. For XML Views, there are three kinds of namespace URIs worth mentioning. First, there are the four special namespace URIs corresponding to XDR and SQL XML (all of which begin with urn:schemas-microsoft-com:, followed by one of xml-data, datatypes, xml-sql, or xml-updategram) that identify schema contents or annotations, respectively. Second, there are external schema references, which we will explain next. And finally, everything else – which are treated as ordinary namespace names. External schema references are distinguished from ordinary namespace URIs by beginning with the string x-schema:. Every such namespace URI is treated as a reference to a schema at the file location listed after the colon. The external schema will be loaded, and all its ElementType and AttributeType declarations made available to the schema that imported it (and in fact, all of the schemas currently being processed). The following two schemas demonstrate the concept: <! ch15_ex27.xdr > <Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:sql="urn:schemas-microsoft-com:xml-sql"> <ElementType name="Customer" sql:relation="Customers"> <element type="x:Order" xmlns:x="x-schema:ch15_ex28.xdr"> <sql:relationship key-relation="Customers" key="CustomerID" foreign-relation="Orders" foreign-key="CustomerID" /> </element> </ElementType> </Schema> [...]... as a well-formed XML document Essentially, it executes a SQL statement against the specified JDBC data source, serializes the returned JDBC result set as XML, and returns this XML document to the calling client as a string Create the JDBC 2XML. java file and enter the following code: package com.jresources.jdbc; import java.sql.*; import java.util.*; public class JDBC 2XML { public JDBC 2XML( ) { super();... column Field values are pre-processed with the encodeXML() method defined above to ensure compliance with XML encoding rules Once we have looped through the entire result set, we terminate the element, and return the XML document: String writeXML(ResultSet rs) { StringBuffer strResults = new StringBuffer ("< ?xml version=\"1.0\" encoding=\"ISO -88 59-1\"?>\r\n\r\n"); try { ResultSetMetaData... store through the XML View by inserting, deleting, or updating XML fragments Updategrams, XPaths, and ordinary SQL queries can be executed from XML templates, and the results from these queries substituted into the XML template Combined with other standard XML processing techniques (such as XSL), these query languages provide a powerful way to transport and present XML data on the Web 624 XML Views in SQL... start Tomcat ❑ Point your browser to http://127.0.0.1 :80 80 By default, Tomcat's HTTP server listens on port 80 80 to preclude any conflict with a web server that might already be installed on your system and listening on port 80 Of course, you can change the port assignment, if desired, by editing the server .xml configuration file (see the Tomcat documentation for more details) When you hit this URL,... this, we will create a simple XML gateway architecture for JDBC Our Simple XML Gateway Architecture for JDBC The heart of our XML gateway architecture for JDBC is the JDBC 2XML class This class controls access to the JDBC data source Briefly, it executes a SQL statement against the specified JDBC data source, serializes the returned JDBC result set as XML, and returns this XML document to the calling client... following figure shows this architecture: 632 JDBC A Simple XML Gateway Architecture for JDBC Web browser XML- enabled Application HTTP GET or POST XML over HTTP HTML over HTTP HTTP GET or POST Delegated to XSL Stylesheet XMLDataGateway Servlet In-process call XSLT XML serialized resultset JDBC2HTML Servlet In-process call XML serialized resultset JDBC 2XML Class JDBC JDBC Data Source This section will walk.. .XML Views in SQL Server 2000 28. xdr > Together, these schemas produce XML shaped like this: ... implement each method Applying XML Encoding Rules to the Result Set Data The encodeXML() method is a generic method that allows you to apply XML encoding rules to certain special characters A well-formed XML document with element or attribute values containing these special characters must be specially encoded to escape them out Otherwise, an XML parser will not be able to process the document This table shows... Metadata and Data as XML The next step is to add code to our JDBC 2XML class that serializes a JDBC result set to XML To accomplish this, we need to do two things: design an XML data structure that encapsulates the data and metadata of a result set, and implement the writeXML() method that performs the actual serialization Designing the XML Structure The first step is to define an XML data structure... structure of our XML document: < ?xml version="1.0" encoding="ISO -88 59-1"?> 635 Chapter 16 field's value goes here Implementing the writeXML() Method The writeXML() method serializes the . /> </element> </ElementType> </Schema> XML Views in SQL Server 2000 621 <! ch15_ex 28. xdr > <Schema xmlns="urn:schemas-microsoft-com :xml- data" xmlns:sql="urn:schemas-microsoft-com :xml- sql"> <ElementType. the table: <Schema xmlns="urn:schemas-microsoft-com :xml- data" xmlns:dt="urn:schemas-microsoft-com:datatypes" xmlns:sql="urn:schemas-microsoft-com :xml- sql"> <ElementType. use a target namespace: <! ch15_ex28a.xdr > <Schema xmlns="urn:schemas-microsoft-com :xml- data" xmlns:sql="urn:schemas-microsoft-com :xml- sql" sql:target-namespace="your