001: /* Copyright 2004 The Apache Software Foundation
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.apache.xmlbeans.samples.enumeration;
017:
018: import org.apache.xmlbeans.XmlError;
019: import org.apache.xmlbeans.XmlException;
020: import org.apache.xmlbeans.XmlObject;
021: import org.apache.xmlbeans.XmlOptions;
022: import org.apache.xmlbeans.samples.enumeration.schemaenum.easypo.LineItem;
023: import org.apache.xmlbeans.samples.enumeration.schemaenum.easypo.PurchaseOrderDocument;
024: import org.apache.xmlbeans.samples.enumeration.schemaenum.pricesummary.ItemType;
025: import org.apache.xmlbeans.samples.enumeration.schemaenum.pricesummary.PriceSummaryDocument;
026: import org.apache.xmlbeans.samples.enumeration.schemaenum.pricesummary.PriceType;
027:
028: import java.io.File;
029: import java.io.IOException;
030: import java.util.ArrayList;
031:
032: /**
033: * This sample illustrates how you can access XML values that are
034: * defined in schema as enumerations. When a schema containing
035: * enumerations is compiled, the generated Java types represent the
036: * schema enumerations with Java enumerations. You can access these through
037: * their constants and corresponding int values.
038: * <p/>
039: * The schemas used by this sample are defined in PriceSummary.xsd and
040: * EasyPO.xsd.
041: */
042: public class SchemaEnum {
043: /**
044: * Receives an PO XML instance and uses its data to create an XML
045: * document based another schema, and which summarizes the items
046: * in the PO by price.
047: *
048: * @param args An array containing one argument: the path to an XML instance
049: * conforming to the schema in EasyPO.xsd.
050: */
051: public static void main(String[] args) {
052: // Create an instance of this class to work with.
053: SchemaEnum this Sample = new SchemaEnum();
054:
055: // Create an instance of a type based on the received XML's schema
056: // and use it to print what the sample received.
057: PurchaseOrderDocument poDoc = this Sample.parseXml(args[0]);
058: System.out.println("Received XML: \n\n" + poDoc.toString());
059:
060: // Print the summarized items in XML based on a different schema.
061: PriceSummaryDocument summaryDoc = this Sample
062: .summarizeItems(poDoc);
063: System.out.println("Summarized items: \n\n"
064: + summaryDoc.toString());
065:
066: // Print a simple non-XML list of items by threshold.
067: String sortedItems = this Sample.sortByThreshold(summaryDoc);
068: System.out.println("Sorted items: \n" + sortedItems);
069:
070: // Validate the result.
071: System.out.println("New XML is valid: "
072: + this Sample.validateXml(summaryDoc));
073: }
074:
075: /**
076: * <p>This method uses values in the incoming XML to construct
077: * a new XML document of a different schema. PriceSummary.xsd, the schema
078: * for the new document, defines XML enumerations for a price
079: * threshold attribute. Items whose price is between $10 and $20 receive
080: * a threshold value of "Between10And20Dollars"; items above 20 get a threshold
081: * value of "Above20Dollars".</p>
082: * <p/>
083: * <p>This method loops through the purchase order items, creating a summary
084: * document that specifies their threshold value.</p>
085: * <p/>
086: * <p>You can verify this method's work by comparing the resulting XML with
087: * the XML in PriceSummary.xml. You can also use this method's return value
088: * to test the sortByThreshold method.</p>
089: */
090: public PriceSummaryDocument summarizeItems(
091: PurchaseOrderDocument poDoc) {
092: PurchaseOrderDocument.PurchaseOrder po = poDoc
093: .getPurchaseOrder();
094:
095: // Create a new instance of the PriceSummary schema. This is the document
096: // the code creates, extracting values from the purchase order.
097: PriceSummaryDocument summaryDoc = PriceSummaryDocument.Factory
098: .newInstance();
099: PriceSummaryDocument.PriceSummary summary = summaryDoc
100: .addNewPriceSummary();
101:
102: // Create <price> elements to hold <item> elements according to their
103: // price threshold.
104: PriceType priceZero = summary.addNewPrice();
105: PriceType priceTen = summary.addNewPrice();
106: PriceType priceTwenty = summary.addNewPrice();
107:
108: // Set the threshold attribute value for the two new elements.
109: priceZero.setThreshold(PriceType.Threshold.BELOW_10_DOLLARS);
110: priceTen
111: .setThreshold(PriceType.Threshold.BETWEEN_10_AND_20_DOLLARS);
112: priceTwenty.setThreshold(PriceType.Threshold.ABOVE_20_DOLLARS);
113:
114: // Loop through the purchase order <line-item> elements. If their
115: // <price> child element is between 10.00 and 20.00, add the <line-item>
116: // to the <price> element whose threshold is 10.00. For those over 20.00,
117: // add them to the <price> element whose threshold is 20.00.
118:
119: // There don't happen to be any under 10.00, but handle this case anyway.
120: LineItem[] items = po.getLineItemArray();
121: for (int i = 0; i < items.length; i++) {
122: LineItem item = items[i];
123:
124: if (item.getPrice() < 10.00) {
125:
126: ItemType newItem = priceZero.addNewItem();
127: newItem.setTitle(item.getDescription());
128: newItem.xsetQuantity(item.xgetQuantity());
129: newItem.setAmount(item.getPrice());
130:
131: } else if (item.getPrice() >= 10.00
132: && item.getPrice() < 20.00) {
133:
134: ItemType newItem = priceTen.addNewItem();
135: newItem.setTitle(item.getDescription());
136: newItem.xsetQuantity(item.xgetQuantity());
137: newItem.setAmount(item.getPrice());
138:
139: } else if (item.getPrice() >= 20.00) {
140:
141: ItemType newItem = priceTwenty.addNewItem();
142: newItem.setTitle(item.getDescription());
143: newItem.xsetQuantity(item.xgetQuantity());
144: newItem.setAmount(item.getPrice());
145: }
146: }
147: return summaryDoc;
148: }
149:
150: /**
151: * <p>This method loops through a price summary XML document to
152: * create a string that lists the items grouped by threshold.
153: * Unlike the summarizeItems method, which creates a new XML
154: * document that contains an attribute whose value is enumerated,
155: * this method retrieves values from an enumeration.</p>
156: * <p/>
157: * <p>This method illustrates how you can use the int value corresponding
158: * to enumerations to specify them in Java switch statements.</p>
159: */
160: public String sortByThreshold(PriceSummaryDocument summaryDoc) {
161: // Extract the summary element from the incoming XML, then use it
162: // to extract an array of the price elements.
163: PriceSummaryDocument.PriceSummary summary = summaryDoc
164: .getPriceSummary();
165: PriceType[] priceElements = summary.getPriceArray();
166:
167: StringBuffer responseBuffer = new StringBuffer();
168:
169: // Create string buffers to hold the sorted results of the values
170: // retrieved.
171: StringBuffer zeroBuffer = new StringBuffer(
172: "\nItems under 10 dollars: \n");
173: StringBuffer tenBuffer = new StringBuffer(
174: "\nItems between 10 and 20 dollars: \n");
175: StringBuffer twentyBuffer = new StringBuffer(
176: "\nItems more than 20 dollars: \n");
177:
178: // Loop through the price elements, extracting the array of <item> child
179: // elements in each.
180: for (int i = 0; i < priceElements.length; i++) {
181: ItemType[] itemElements = priceElements[i].getItemArray();
182:
183: // Loop through the <item> elements, discovering which threshold
184: // the item belongs to, then using the element's <title> value
185: // in in a sorted list.
186: for (int j = 0; j < itemElements.length; j++) {
187: ItemType item = itemElements[j];
188:
189: // For each <item> element, find out the int value of its <price>
190: // parent element's threshold attribute value. Append the item's
191: // title to the appropriate string buffer.
192: switch (priceElements[i].getThreshold().intValue()) {
193:
194: case PriceType.Threshold.INT_BELOW_10_DOLLARS:
195: zeroBuffer.append(" " + item.getTitle() + "\n");
196: break;
197:
198: case PriceType.Threshold.INT_BETWEEN_10_AND_20_DOLLARS:
199: tenBuffer.append(" " + item.getTitle() + "\n");
200: break;
201:
202: case PriceType.Threshold.INT_ABOVE_20_DOLLARS:
203: twentyBuffer.append(" " + item.getTitle() + "\n");
204: break;
205:
206: default:
207: System.out
208: .println("Yo! Something unexpected happened!");
209: break;
210: }
211: }
212: }
213: responseBuffer.append(tenBuffer);
214: responseBuffer.append(twentyBuffer);
215: return responseBuffer.toString();
216: }
217:
218: /**
219: * <p>Validates the XML, printing error messages when the XML is invalid. Note
220: * that this method will properly validate any instance of a compiled schema
221: * type because all of these types extend XmlObject.</p>
222: * <p/>
223: * <p>Note that in actual practice, you'll probably want to use an assertion
224: * when validating if you want to ensure that your code doesn't pass along
225: * invalid XML. This sample prints the generated XML whether or not it's
226: * valid so that you can see the result in both cases.</p>
227: *
228: * @param xml The XML to validate.
229: * @return <code>true</code> if the XML is valid; otherwise, <code>false</code>
230: */
231: public boolean validateXml(XmlObject xml) {
232: boolean isXmlValid = false;
233:
234: // A collection instance to hold validation error messages.
235: ArrayList validationMessages = new ArrayList();
236:
237: // Validate the XML, collecting messages.
238: isXmlValid = xml.validate(new XmlOptions()
239: .setErrorListener(validationMessages));
240:
241: if (!isXmlValid) {
242: System.out.println("Invalid XML: ");
243: for (int i = 0; i < validationMessages.size(); i++) {
244: XmlError error = (XmlError) validationMessages.get(i);
245: System.out.println(error.getMessage());
246: System.out.println(error.getObjectLocation());
247: }
248: }
249: return isXmlValid;
250: }
251:
252: /**
253: * <p>Creates a File from the XML path provided in main arguments, then
254: * parses the file's contents into a type generated from schema.</p>
255: * <p/>
256: * <p>Note that this work might have been done in main. Isolating it here
257: * makes the code separately available from outside this class.</p>
258: *
259: * @param xmlFilePath A path to XML based on the schema in inventory.xsd.
260: * @return An instance of a generated schema type that contains the parsed
261: * XML.
262: */
263: public PurchaseOrderDocument parseXml(String xmlFilePath) {
264: File poFile = new File(xmlFilePath);
265: PurchaseOrderDocument poDoc = null;
266: try {
267: poDoc = PurchaseOrderDocument.Factory.parse(poFile);
268: } catch (XmlException e) {
269: e.printStackTrace();
270: } catch (IOException e) {
271: e.printStackTrace();
272: }
273: return poDoc;
274: }
275: }
|