blob: 50d6f50f7034165da51699cf7409392c8d102b4c [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xmlbeans.samples.enumeration;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.samples.enumeration.schemaenum.easypo.LineItem;
import org.apache.xmlbeans.samples.enumeration.schemaenum.easypo.PurchaseOrderDocument;
import org.apache.xmlbeans.samples.enumeration.schemaenum.pricesummary.ItemType;
import org.apache.xmlbeans.samples.enumeration.schemaenum.pricesummary.PriceSummaryDocument;
import org.apache.xmlbeans.samples.enumeration.schemaenum.pricesummary.PriceType;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
/**
* This sample illustrates how you can access XML values that are
* defined in schema as enumerations. When a schema containing
* enumerations is compiled, the generated Java types represent the
* schema enumerations with Java enumerations. You can access these through
* their constants and corresponding int values.
* <p/>
* The schemas used by this sample are defined in PriceSummary.xsd and
* EasyPO.xsd.
*/
public class SchemaEnum
{
/**
* Receives an PO XML instance and uses its data to create an XML
* document based another schema, and which summarizes the items
* in the PO by price.
*
* @param args An array containing one argument: the path to an XML instance
* conforming to the schema in EasyPO.xsd.
*/
public static void main(String[] args)
{
// Create an instance of this class to work with.
SchemaEnum thisSample = new SchemaEnum();
// Create an instance of a type based on the received XML's schema
// and use it to print what the sample received.
PurchaseOrderDocument poDoc = thisSample.parseXml(args[0]);
System.out.println("Received XML: \n\n" + poDoc.toString());
// Print the summarized items in XML based on a different schema.
PriceSummaryDocument summaryDoc = thisSample.summarizeItems(poDoc);
System.out.println("Summarized items: \n\n" + summaryDoc.toString());
// Print a simple non-XML list of items by threshold.
String sortedItems = thisSample.sortByThreshold(summaryDoc);
System.out.println("Sorted items: \n" + sortedItems);
// Validate the result.
System.out.println("New XML is valid: " +
thisSample.validateXml(summaryDoc));
}
/**
* <p>This method uses values in the incoming XML to construct
* a new XML document of a different schema. PriceSummary.xsd, the schema
* for the new document, defines XML enumerations for a price
* threshold attribute. Items whose price is between $10 and $20 receive
* a threshold value of "Between10And20Dollars"; items above 20 get a threshold
* value of "Above20Dollars".</p>
* <p/>
* <p>This method loops through the purchase order items, creating a summary
* document that specifies their threshold value.</p>
* <p/>
* <p>You can verify this method's work by comparing the resulting XML with
* the XML in PriceSummary.xml. You can also use this method's return value
* to test the sortByThreshold method.</p>
*/
public PriceSummaryDocument summarizeItems(PurchaseOrderDocument poDoc)
{
PurchaseOrderDocument.PurchaseOrder po = poDoc.getPurchaseOrder();
// Create a new instance of the PriceSummary schema. This is the document
// the code creates, extracting values from the purchase order.
PriceSummaryDocument summaryDoc = PriceSummaryDocument.Factory.newInstance();
PriceSummaryDocument.PriceSummary summary = summaryDoc.addNewPriceSummary();
// Create <price> elements to hold <item> elements according to their
// price threshold.
PriceType priceZero = summary.addNewPrice();
PriceType priceTen = summary.addNewPrice();
PriceType priceTwenty = summary.addNewPrice();
// Set the threshold attribute value for the two new elements.
priceZero.setThreshold(PriceType.Threshold.BELOW_10_DOLLARS);
priceTen.setThreshold(PriceType.Threshold.BETWEEN_10_AND_20_DOLLARS);
priceTwenty.setThreshold(PriceType.Threshold.ABOVE_20_DOLLARS);
// Loop through the purchase order <line-item> elements. If their
// <price> child element is between 10.00 and 20.00, add the <line-item>
// to the <price> element whose threshold is 10.00. For those over 20.00,
// add them to the <price> element whose threshold is 20.00.
// There don't happen to be any under 10.00, but handle this case anyway.
LineItem[] items = po.getLineItemArray();
for (int i = 0; i < items.length; i++)
{
LineItem item = items[i];
if (item.getPrice() < 10.00)
{
ItemType newItem = priceZero.addNewItem();
newItem.setTitle(item.getDescription());
newItem.xsetQuantity(item.xgetQuantity());
newItem.setAmount(item.getPrice());
} else if (item.getPrice() >= 10.00 && item.getPrice() < 20.00)
{
ItemType newItem = priceTen.addNewItem();
newItem.setTitle(item.getDescription());
newItem.xsetQuantity(item.xgetQuantity());
newItem.setAmount(item.getPrice());
} else if (item.getPrice() >= 20.00)
{
ItemType newItem = priceTwenty.addNewItem();
newItem.setTitle(item.getDescription());
newItem.xsetQuantity(item.xgetQuantity());
newItem.setAmount(item.getPrice());
}
}
return summaryDoc;
}
/**
* <p>This method loops through a price summary XML document to
* create a string that lists the items grouped by threshold.
* Unlike the summarizeItems method, which creates a new XML
* document that contains an attribute whose value is enumerated,
* this method retrieves values from an enumeration.</p>
* <p/>
* <p>This method illustrates how you can use the int value corresponding
* to enumerations to specify them in Java switch statements.</p>
*/
public String sortByThreshold(PriceSummaryDocument summaryDoc)
{
// Extract the summary element from the incoming XML, then use it
// to extract an array of the price elements.
PriceSummaryDocument.PriceSummary summary = summaryDoc.getPriceSummary();
PriceType[] priceElements = summary.getPriceArray();
StringBuilder responseBuffer = new StringBuilder();
// Create string buffers to hold the sorted results of the values
// retrieved.
StringBuilder zeroBuffer = new StringBuilder("\nItems under 10 dollars: \n");
StringBuilder tenBuffer = new StringBuilder("\nItems between 10 and 20 dollars: \n");
StringBuilder twentyBuffer = new StringBuilder("\nItems more than 20 dollars: \n");
// Loop through the price elements, extracting the array of <item> child
// elements in each.
for (int i = 0; i < priceElements.length; i++)
{
ItemType[] itemElements = priceElements[i].getItemArray();
// Loop through the <item> elements, discovering which threshold
// the item belongs to, then using the element's <title> value
// in in a sorted list.
for (int j = 0; j < itemElements.length; j++)
{
ItemType item = itemElements[j];
// For each <item> element, find out the int value of its <price>
// parent element's threshold attribute value. Append the item's
// title to the appropriate string buffer.
switch (priceElements[i].getThreshold().intValue())
{
case PriceType.Threshold.INT_BELOW_10_DOLLARS:
zeroBuffer.append(" " + item.getTitle() + "\n");
break;
case PriceType.Threshold.INT_BETWEEN_10_AND_20_DOLLARS:
tenBuffer.append(" " + item.getTitle() + "\n");
break;
case PriceType.Threshold.INT_ABOVE_20_DOLLARS:
twentyBuffer.append(" " + item.getTitle() + "\n");
break;
default:
System.out.println("Yo! Something unexpected happened!");
break;
}
}
}
responseBuffer.append(tenBuffer);
responseBuffer.append(twentyBuffer);
return responseBuffer.toString();
}
/**
* <p>Validates the XML, printing error messages when the XML is invalid. Note
* that this method will properly validate any instance of a compiled schema
* type because all of these types extend XmlObject.</p>
* <p/>
* <p>Note that in actual practice, you'll probably want to use an assertion
* when validating if you want to ensure that your code doesn't pass along
* invalid XML. This sample prints the generated XML whether or not it's
* valid so that you can see the result in both cases.</p>
*
* @param xml The XML to validate.
* @return <code>true</code> if the XML is valid; otherwise, <code>false</code>
*/
public boolean validateXml(XmlObject xml)
{
boolean isXmlValid = false;
// A collection instance to hold validation error messages.
ArrayList validationMessages = new ArrayList();
// Validate the XML, collecting messages.
isXmlValid = xml.validate(new XmlOptions().setErrorListener(validationMessages));
if (!isXmlValid)
{
System.out.println("Invalid XML: ");
for (int i = 0; i < validationMessages.size(); i++)
{
XmlError error = (XmlError) validationMessages.get(i);
System.out.println(error.getMessage());
System.out.println(error.getObjectLocation());
}
}
return isXmlValid;
}
/**
* <p>Creates a File from the XML path provided in main arguments, then
* parses the file's contents into a type generated from schema.</p>
* <p/>
* <p>Note that this work might have been done in main. Isolating it here
* makes the code separately available from outside this class.</p>
*
* @param xmlFilePath A path to XML based on the schema in inventory.xsd.
* @return An instance of a generated schema type that contains the parsed
* XML.
*/
public PurchaseOrderDocument parseXml(String xmlFilePath)
{
File poFile = new File(xmlFilePath);
PurchaseOrderDocument poDoc = null;
try
{
poDoc = PurchaseOrderDocument.Factory.parse(poFile);
} catch (XmlException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return poDoc;
}
}