/* * Copyright 2001-2014 Aspose Pty Ltd. All Rights Reserved. * * This file is part of Aspose.Words. The source code in this file * is only intended as a supplement to the documentation, and is provided * "as is", without warranty of any kind, either expressed or implied. */ package com.aspose.words.examples.asposefeatures.mailmerge.mailmergefromxmldatasource; import com.aspose.words.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import java.util.HashMap; /** * A custom mail merge data source that allows you to merge data from an XML document into Word templates. * This class demonstrates how data can be read from a custom data source (XML parsed and loaded into a DOM) and merged * into a document using the IMailMergeDataSource interface. * * An instance of this class represents a single table in the data source and in the template. * Note: We are using the Document and Node class from the org.w3c.dom package here and not from Aspose.Words. */ public class XmlMailMergeDataTable implements IMailMergeDataSource { /** * Creates a new XmlMailMergeDataSource for the specified XML document and table name. * * @param xmlDoc The DOM object which contains the parsed XML data. * @param tableName The name of the element in the data source where the data of the region is extracted from. */ public XmlMailMergeDataTable(org.w3c.dom.Document xmlDoc, String tableName) throws Exception { this(xmlDoc.getDocumentElement(), tableName); } /** * Private constructor that is also called by GetChildDataSource. */ private XmlMailMergeDataTable(Node rootNode, String tableName) throws Exception { mTableName = tableName; // Get the first element on this level matching the table name. mCurrentNode = (Node)retrieveExpression("./" + tableName).evaluate(rootNode, XPathConstants.NODE); } /** * The name of the data source. Used by Aspose.Words only when executing mail merge with repeatable regions. */ public String getTableName() { return mTableName; } /** * Aspose.Words calls this method to get a value for every data field. */ public boolean getValue(String fieldName, Object[] fieldValue) throws Exception { // Attempt to retrieve the child node matching the field name by using XPath. Node value = (Node)retrieveExpression(fieldName).evaluate(mCurrentNode, XPathConstants.NODE); // We also look for the field name in attributes of the element node. Element nodeAsElement = (Element)mCurrentNode; if (value != null) { // Field exists in the data source as a child node, pass the value and return true. // This merges the data into the document. fieldValue[0] = value.getTextContent(); return true; } else if (nodeAsElement.hasAttribute(fieldName)) { // Field exists in the data source as an attribute of the current node, pass the value and return true. // This merges the data into the document. fieldValue[0] = nodeAsElement.getAttribute(fieldName); return true; } else { // Field does not exist in the data source, return false. // No value will be merged for this field and it is left over in the document. return false; } } /** * Moves to the next record in a collection. This method is a little different then the regular implementation as * we are walking over an XML document stored in a DOM. */ public boolean moveNext() { if (!isEof()) { // Don't move to the next node if this the first record to be merged. if (!mIsFirstRecord) { // Find the next node which is an element and matches the table name represented by this class. // This skips any text nodes and any elements which belong to a different table. do { mCurrentNode = mCurrentNode.getNextSibling(); } while ((mCurrentNode != null) && !(mCurrentNode.getNodeName().equals(mTableName) && (mCurrentNode.getNodeType() == Node.ELEMENT_NODE))); } else { mIsFirstRecord = false; } } return (!isEof()); } /** * If the data source contains nested data this method will be called to retrieve the data for * the child table. In the XML data source nested data this should look like this: * * <Tables> * <ParentTable> * <Name>ParentName</Name> * <ChildTable> * <Text>Content</Text> * </ChildTable> * </ParentTable> * </Tables> */ public IMailMergeDataSource getChildDataSource(String tableName) throws Exception { return new XmlMailMergeDataTable(mCurrentNode, tableName); } private boolean isEof() { return (mCurrentNode == null); } /** * Returns a cached version of a compiled XPathExpression if available, otherwise creates a new expression. */ private XPathExpression retrieveExpression(String path) throws Exception { XPathExpression expression; if(mExpressionSet.containsKey(path)) { expression = (XPathExpression)mExpressionSet.get(path); } else { expression = mXPath.compile(path); mExpressionSet.put(path, expression); } return expression; } /** * Instance variables. */ private Node mCurrentNode; private boolean mIsFirstRecord = true; private final String mTableName; private final HashMap mExpressionSet = new HashMap(); private final XPath mXPath = XPathFactory.newInstance().newXPath(); } //ExEnd