The elements which are used in the form message type for a specific form can be classfied as four types:
- direct binding.
Example: in direct binding, the element path is just specified in the attribute “field.bind.ref”, as shown below.
<field access="readOnly" minH="6.2mm" name="txtCustomerID" w="85mm">
<font typeface="Arial"/>
<margin bottomInset="1.2mm" leftInset="0mm" rightInset="0mm" topInset="0mm"/>
<caption reserve="39mm">
<font typeface="Arial" weight="bold"/>
<value>
<text>Customer ID:</text>
</value>
</caption>
<bind match="dataRef" ref="$record.DeliveryNote.ProductRecipientParty.InternalID"/>
<sapa1s xmlns="http://www.sap.com/a1s/cd/om/forms/config"><InfoBlockItem configurable="false" copyForCustomFields="false"><Description lang="en">Customer ID</Description></InfoBlockItem></sapa1s>
</field>
- relative binding.
Example: form template field form message type instance
A ( parent ) $record.DeliveryNote.Material
a ( child ) $.ID
b ( child ) $.ItemID
c ( child ) $.Name
If some node in the same hierarchy are bound to the same parent node in the form message type, for this example “a” is bound to $record.DeliveryNote.Material.ID and “b” is bound to $record.DeliveryNote.Material.ItemID and “c” is bound to $record.DeliveryNote.Material.Name. To enhance performance, we use relative binding. The parent of a,b, and c is bound to $record.DeliveryNote.Material and “a” now is bound to $.ID and “b” $.ItemID and “c” $.Name.
<field access="readOnly" minH="2mm" name="colIndex" w="30mm" x="0mm" y="0mm">
<font size="9pt" typeface="Arial"/>
<margin bottomInset="1mm" leftInset="1mm" rightInset="1mm" topInset="1mm"/>
<bind match="dataRef" ref="$.ItemID"/>
<assist>
<speak disable="1"/>
</assist>
</field>
- direct scripting.
As mentioned by Patrick, it is impossible to fulfill some special requirement sometimes so java script is used to handle with some form message type elements.
All the script texts for a field is located in the field.event.script node in the xml source.
We call some type as “direct scripting” because the specified form message type elements can still be found in the script text, as example below:
$DeliveryNote.LogisticPackage.Material.PurchaseOrderItemReference.ID ( just concatenate the path after “resolveNode” function ).
- relative scripting.
We call “relative scripting” because the path of the form message type elements used is more implicit to be detected compared with direct scripting. Relative scripting is mainly used to benefit from making table accessible and EFE compatible.
Example: var d = this.dataNode.parent.parent.
We cannot get anything from the script above until going up in the form message type instance hierarchy. Field “txtLUID” is relatively bound to “TargetLogisticsAreaDescription”.
So we can know that in this script, the element LogisticPackage.LogisticUnitID and LogisticPackage.PlannedLogisticUnitQuantity is used.
To achieve this:
step1: load the xml source of a template into memory. You can find that I just ignore the xml source " content balalala" because those source are irrrelevant for field binding path and the more important thing is , I find the Java DOM can not handle with some special locale characters, for example ,the locale characters in Chinese, so I just ignore them.
if( CheckifXDPFile(inputXDPFile) == false )
return null;
String XMLOutput = getFileNameExcludingExt(inputXDPFile);
XMLOutput += ".xml";
br = new BufferedReader(new FileReader(inputXDPFile));
bw = new BufferedWriter(new FileWriter(XMLOutput));
System.out.println("Begin to Copy File");
File XML = new File(inputXDPFile);
int length = (int)XML.length();
char[] inputdata = new char [length];
br.read(inputdata,0,length);
String input = new String(inputdata);
int indexlocale = input.indexOf("<localeSet");
if( indexlocale == -1)
{
// the template has no localeSet node!
bw.write(inputdata);
br.close();
bw.close();
return XMLOutput;
}
String before = input.substring(0,indexlocale);
int postindex = input.indexOf("</localeSet>");
String locale = "</localeSet>";
String post = input.substring(postindex + locale.length());
String finalString = before.concat(post);
bw.write(finalString);
br.close();
bw.close();
return XMLOutput;
step2: build the xml source got from step1 into DOM tree.
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
private DocumentBuilderFactory domfac;
private DocumentBuilder dombuilder;
private Document doc;
InputStream inputXML = new FileInputStream(OutputXMLFile);
doc = dombuilder.parse(inputXML);
Element root = doc.getDocumentElement();
Node template = Tool.getNodebyRoot("template",root);
if( template == null)
return null;
An example of DOM tree looks like below. Here what you have to do is just to go through the node for master page and the one for body page recursively and get all the subnode filtered by node name “field”.
This is because only element “field” and “subform” can have binding path from technical side, if you need also to extract binding path of subform, you must also handle with the node whose name is “subform”.
step3: suppose you have already get a node for “field”, you can find from the xml source for this field below and know that the binding path is located in the subnode named “bind”, attribute “ref”.
<field access="readOnly" minH="6.2mm" name="txtLogLocation1" w="85mm">
<ui>
<textEdit multiLine="1">
</textEdit>
</ui>
<font baselineShift="0pt" typeface="Arial"/>
<margin bottomInset="0mm" leftInset="0mm" rightInset="0mm" topInset="0mm"/>
<caption reserve="40mm">
<font baselineShift="0pt" typeface="Arial" weight="bold"/>
<value>
<text> </text>
</value>
</caption>
<bind match="dataRef" ref="$record.SiteLogisticsTask.LogisticsLocationDescription"/>
<assist>
<speak priority="caption"/>
</assist>
you can get its binding path such as below:
private void getFieldBindingInfo(Node node)
{
Node BindNode = Tool.getNodebyRoot("bind",node);
if( BindNode == null)
{
// this node has none binding path at all !!
return;
}
else
{
if( BindNode.getAttributes().getNamedItem("ref") == null)
// none binding
{
return;
}
else
{
bindingPath = BindNode.getAttributes().getNamedItem("ref").getNodeValue();
// bind path is stored in bindingPath!
}
}
whole source code
package formAutoBinding;
import utilities.*;
import excelFormat.internalStructure.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Vector;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class TemplateBindingProcessor
{
private DocumentBuilderFactory domfac;
private DocumentBuilder dombuilder;
private FileCopyFactory filecopy;
private Document doc;
private Element root;
private String tablePath = null;
private HashMap<String,internalPathObject> bindingpathCollection = null;
private Vector<String> TableCellNameVec = null;
private Vector<String> NormalBindingVec = null;
private Vector<String> NoneBindingVec = null;
private JList jListforBindingInfo = null;
private DefaultListModel listModeforBindingInfo = null;
private int nBoundFieldNumber = 0;
private int nUnBoundFieldNumber = 0;
public TemplateBindingProcessor(HashMap<String,internalPathObject> collection)
{
bindingpathCollection = collection;
domfac = DocumentBuilderFactory.newInstance();
NormalBindingVec = new Vector<String>();
NoneBindingVec = new Vector<String>();
try
{
dombuilder = domfac.newDocumentBuilder();
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
}
}
public Element getRoot()
{
return root;
}
private String comparePrefix(String pre1,String pre2)
{
System.out.println("Compare pre1: " + pre1 + " pre2: " + pre2);
if(( pre1 == null) || ( pre2 == null))
return null;
return pre1.length() > pre2.length()? pre2:pre1;
}
private String getMaxPrefix(Vector<String> c)
{
int size = c.size();
if( size <= 1)
{
System.out.println("Only : " + size + " elements in the table!");
return null;
}
String s1 = c.elementAt(0);
String s2 = c.elementAt(1);
String finalprefix = null;
String tempprefix = getMaxPrefixwithTwoString(s1,s2);
for( int i = 2 ; i < size; i++ )
{
s1 = tempprefix;
s2 = c.elementAt(i);
finalprefix = getMaxPrefixwithTwoString(s1,s2);
finalprefix = comparePrefix(tempprefix,finalprefix);
}
if( finalprefix == null)
System.out.println("Error: Can not find Table Row Binding Path");
else
System.out.println("Table Path: " + finalprefix);
return finalprefix;
}
private String getMaxPrefixwithTwoString(String n1,String n2)
{
int length1 = n1.length();
int length2 = n2.length();
int i = 0;
while(i < length1 && i < length2)
{
if( n1.charAt(i) != n2.charAt(i))
break;
i++;
}
if( i == 0 )
return null;
String temp = n1.substring(0,i);
System.out.println("String1: " + n1 + " String2: " + n2 + " prefix->" + temp);
return temp;
}
public void PrintBindingStatistics(JList jlist,DefaultListModel mode)
{
jListforBindingInfo = jlist;
listModeforBindingInfo = mode;
listModeforBindingInfo.clear();
jListforBindingInfo.setModel(listModeforBindingInfo);
Node templateNode = Tool.getNodebyRoot("template",root);
if( templateNode == null )
return;
traverse(templateNode);
String item = "Total Bound Field Number: " + nBoundFieldNumber;
listModeforBindingInfo.addElement(item);
item = "Total Unbound Field Number: " + nUnBoundFieldNumber;
listModeforBindingInfo.addElement(item);
listModeforBindingInfo.addElement("\n");
int normalBindingNumber = NormalBindingVec.size();
for( int i = 0 ; i < normalBindingNumber; i++)
{
item = "Field: " + NormalBindingVec.elementAt(i) + " has normal binding!";
listModeforBindingInfo.addElement(item);
listModeforBindingInfo.addElement("\n");
}
int noneBindingNumber = NoneBindingVec.size();
for( int j = 0 ; j < noneBindingNumber; j++)
{
item = "Field: " + NoneBindingVec.elementAt(j) + " binding set to NONE!";
listModeforBindingInfo.addElement(item);
listModeforBindingInfo.addElement("\n");
}
}
// save all the information in the listmode into a file
public String SaveLogFile(String path)
{
int index = path.lastIndexOf('.');
if ( index == -1)
path += ".html";
try
{
FileLogFactory log = new FileLogFactory(path);
int lognumber = listModeforBindingInfo.size();
for( int i = 0 ; i < lognumber; i++)
{
log.WriteToLogFile(listModeforBindingInfo.elementAt(i).toString());
}
log.CloseFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return path;
}
private void traverse(Node node)
{
NodeList child = node.getChildNodes();
int childNumber = child.getLength();
Node item = null;
for( int i = 0 ;i < childNumber; i++)
{
item = child.item(i);
if( item.getNodeName().equals("subform") || item.getNodeName().equals("subformSet"))
traverse(item);
else if ( item.getNodeName().equals("field"))
getFieldBindingInfo(item);
else if ( item.getNodeName().equals("pageSet"))
getMasterPageBindingInfo(item);
}
}
private void getFieldBindingInfo(Node node)
{
String fieldName = null;
String bindingPath = null;
if( node.getAttributes().getNamedItem("name") == null )
fieldName = "DefaultField";
else
fieldName = node.getAttributes().getNamedItem("name").getNodeValue();
Node BindNode = Tool.getNodebyRoot("bind",node);
if( BindNode == null)
{
nUnBoundFieldNumber++;
NormalBindingVec.add(fieldName);
}
else
{
if( BindNode.getAttributes().getNamedItem("ref") == null)
// none binding
{
nUnBoundFieldNumber++;
NoneBindingVec.add(fieldName);
}
else
{
bindingPath = BindNode.getAttributes().getNamedItem("ref").getNodeValue();
nBoundFieldNumber++;
String item = "Field: " + fieldName;
listModeforBindingInfo.addElement(item);
item = "Bound to path: " + bindingPath + " Successfully!";
listModeforBindingInfo.addElement(item);
listModeforBindingInfo.addElement("\n");
}
}
}
private void getMasterPageBindingInfo(Node item)
{
NodeList masterChild = item.getChildNodes();
Node masterPageitem = null;
int masterChildLength = masterChild.getLength();
for (int j = 0; j < masterChildLength; j++)
{
masterPageitem = masterChild.item(j);
if (masterPageitem.getNodeName().equals("pageArea"))
{
traverse(masterPageitem);
}
}
}
private boolean isNodeTableRow(Node node)
{
if( Tool.isFieldHidden(node))
return false;
if( node.getNodeName().equals("subformSet"))
return false;
if( node.getAttributes().getNamedItem("layout") == null )
return false;
String layoutStyle = node.getAttributes().getNamedItem("layout").getNodeValue();
if( !layoutStyle.equals("row"))
return false;
// should filter out the header row: for header row need not bind at all
int fieldNumber = 0;
NodeList child = node.getChildNodes();
int childnumber = child.getLength();
for( int i = 0 ; i < childnumber; i++)
{
if( child.item(i).getNodeName().equals("field"))
fieldNumber++;
}
if( fieldNumber == 0 )
{
System.out.println("This node need not bind!");
return false;
}
return true;
}
private void BindTableRow(Node node)
{
NodeList child = node.getChildNodes();
int childnumber = child.getLength();
Node item = null;
String fieldName = null;
internalPathObject pathObj = null;
TableCellNameVec = new Vector<String>();
for( int i = 0 ; i < childnumber;i++)
{
item = child.item(i);
if( item.getNodeName().equals("field"))
{
fieldName = FetchFieldDefaultValue(item);
// get path
pathObj = bindingpathCollection.get(fieldName);
/* this situation means some fields are not bound directly but
* its value is assigned through some else fields within hidden field
*/
if( pathObj == null)
continue;
System.out.println("Adding Table Cell Path:" + pathObj.getPath());
TableCellNameVec.add(pathObj.getPath());
}
// also search the field path within the hidden subform
else if (( item.getNodeName().equals("subform")) && ( Tool.isFieldHidden(item)))
{
// get all the fields within hidden subform
RecursiveFillFieldName(item);
}
}
tablePath = getMaxPrefix(TableCellNameVec);
TableCellNameVec.clear();
TableCellNameVec = null;
System.out.println("Table Path: " + tablePath);
tablePath = tablePath.substring(0,tablePath.length()-1);
System.out.println("Table Path: " + tablePath);
// append bind node to table node
AppendTableBindNode(node);
}
private void RecursiveFillFieldName(Node node)
{
NodeList child = node.getChildNodes();
int number = child.getLength();
Node item = null;
String fieldName = null;
internalPathObject pathObj = null;
for( int i = 0 ; i < number; i++)
{
item = child.item(i);
if( item.getNodeName().equals("field"))
{
fieldName = FetchFieldDefaultValue(item);
System.out.println("FiledName**********: " + fieldName);
// get path
pathObj = bindingpathCollection.get(fieldName);
/* this situation means some fields are not bound directly but
* its value is assigned through some else fields within hidden field
*/
if( pathObj == null)
continue;
System.out.println("Adding........Table Cell: " + pathObj.getPath());
TableCellNameVec.add(pathObj.getPath());
}
else if ( item.getNodeName().equals("subform"))
RecursiveFillFieldName(item);
}
}
private void AppendTableBindNode(Node item)
{
Node BindNode = Tool.getNodebyRoot("bind",item);
if( BindNode == null) // normal binding
AppendMatchNodeandDoBinding(item,null);
else if( BindNode.getAttributes().getNamedItem("match").getNodeValue().equals("none")) // none binding
ModifyMatchValueandDoBinding(item,BindNode,null);
else // overwrite the previous binding path
OverWritePreviousPath(item,BindNode,null);
}
public void StartTemplateBinding(String path)
{
LoadTemplateFile(path);
System.out.println("Load Template Successfully!");
root = doc.getDocumentElement();
Node templateNode = Tool.getNodebyRoot("template",root);
if( templateNode == null )
return;
System.out.println("Start auto binding!");
AutoBindTemplate(templateNode);
}
private void AutoBindTemplate(Node parent)
{
NodeList child = parent.getChildNodes();
Node item = null;
int childLength = child.getLength();
for (int i = 0; i < childLength; i++)
{
item = child.item(i);
// Should take subform set into consideration
if ((item.getNodeName().equals("subform"))
|| (item.getNodeName().equals("subformSet")))
{
// should dynamically find the max prefix, that is the binding path
// of the table row !
if( isNodeTableRow( item ))
BindTableRow( item );
AutoBindTemplate(item);
}
else if (item.getNodeName().equals("pageSet"))
{
NodeList masterChild = item.getChildNodes();
Node masterPageitem = null;
int masterChildLength = masterChild.getLength();
for (int j = 0; j < masterChildLength; j++)
{
masterPageitem = masterChild.item(j);
if (masterPageitem.getNodeName().equals("pageArea"))
{
HandlePageArea(masterPageitem);
}
}
}
// field not in the table
else if (item.getNodeName().equals("field"))
{
// start real auto binding process here
System.out.println("Detect a field");
AutoBindField(item);
}
}
}
private void HandlePageArea(Node PageArea)
{
NodeList child = PageArea.getChildNodes();
Node item = null;
int childLength = child.getLength();
for (int i = 0; i < childLength; i++)
{
item = child.item(i);
// Should take subform set into consideration
if ((item.getNodeName().equals("subform"))
|| (item.getNodeName().equals("subformSet")))
{
AutoBindTemplate(item);
}
else if (item.getNodeName().equals("field"))
{
//start real auto binding process here
AutoBindField(item);
}
}
}
private String GetDecimalDefaultValue(Node ValueNode)
{
Node decimalNode = Tool.getNodebyRoot("decimal",ValueNode);
if( decimalNode == null)
return null;
return decimalNode.getTextContent();
}
private String FetchFieldDefaultValue(Node node)
{
Node valueNode = Tool.getNodebyRoot("value",node);
if( valueNode == null)
{
System.out.println("Cannot find value node within the field node");
return null;
}
Node textNode = Tool.getNodebyRoot("text",valueNode);
if( textNode == null)
{
System.out.println("Cannot find text node within the value node");
// one more check: if it is a decimal field ?
return GetDecimalDefaultValue(valueNode);
}
System.out.println("Default Value: " + textNode.getTextContent());
return textNode.getTextContent();
}
// Caption Name is a generic definition which means the identificator
// of a field in the template
private void AutoBindField(Node item)
{
String CaptionName = FetchFieldCaption(item);
if( CaptionName == null)
{
CaptionName = FetchFieldDefaultValue(item);
if( CaptionName == null )
return;
}
System.out.println("Field to be auto bound:->" + CaptionName);
internalPathObject obj = bindingpathCollection.get(CaptionName);
if( obj == null )
{
System.out.println("Try to bind field: " + CaptionName + " but fail to find path in PathCollection");
return;
}
Node BindNode = Tool.getNodebyRoot("bind",item);
System.out.println("Field: " + CaptionName + " Path: " + obj.getPath() + " Can be bound now!");
if( BindNode == null) // normal binding
AppendMatchNodeandDoBinding(item,obj);
else if( BindNode.getAttributes().getNamedItem("match").getNodeValue().equals("none")) // none binding
ModifyMatchValueandDoBinding(item,BindNode,obj);
else // overwrite the previous binding path
OverWritePreviousPath(item,BindNode,obj);
}
private void OverWritePreviousPath(Node parentNode,Node OldBindNode,internalPathObject obj)
{
// the same logic as the none-binding
ModifyMatchValueandDoBinding(parentNode,OldBindNode,obj);
}
/* take delivery Note for example, should check if a field is in a table row.
* only in the table row can use relative binding currently. up to 3
* level may be enough.
*/
private boolean checkIfinTableRow(Node node)
{
System.out.println("in CheckIfinTableRow()");
String layoutAttr = null;
Node parent = node.getParentNode();
for( int i = 0 ; i < 3; i++ )
{
if( parent == null )
return false;
if( parent.getAttributes().getNamedItem("layout") == null )
{
parent = parent.getParentNode();
continue;
}
else
{
layoutAttr = parent.getAttributes().getNamedItem("layout").getNodeValue();
if( layoutAttr.equals("row"))
{
System.out.println("Found a table Row: " + parent.getAttributes().getNamedItem("name").getNodeValue());
return true;
}
}
parent = parent.getParentNode();
}
return false;
}
private void ModifyMatchValueandDoBinding(Node parentNode,Node OldBindNode,internalPathObject obj)
{
Document CellDocument = parentNode.getOwnerDocument();
Element NewbindNode = CellDocument.createElement("bind");
Attr matchFlag = CellDocument.createAttribute("match");
matchFlag.setNodeValue("dataRef");
NewbindNode.setAttributeNode(matchFlag);
String realBindPath = null;
if( obj == null)
{
// means it is a table row
realBindPath = tablePath + "[*]";
}
else if( obj.isInTable() )
{
// should use relative path instead
System.out.println("Field: " + obj.getRelativePath() + " is in table");
if( checkIfinTableRow(parentNode))
realBindPath = getRelativePath(obj);
else
{
realBindPath = obj.getPath();
}
}
else
realBindPath = obj.getPath();
Attr Boundpath = CellDocument.createAttribute("ref");
Boundpath.setNodeValue(realBindPath);
NewbindNode.setAttributeNode(Boundpath);
parentNode.replaceChild(NewbindNode, OldBindNode);
System.out.println("Add a New Bind Node");
}
private String getRelativePath(internalPathObject obj)
{
String completePath = obj.getPath();
String relativePath = completePath.substring(tablePath.length(),completePath.length());
System.out.println("Relative Path: " + relativePath);
relativePath = "$" + relativePath;
return relativePath;
}
private void AppendMatchNodeandDoBinding(Node node,internalPathObject obj)
{
Document CellDocument = node.getOwnerDocument();
Element bindNode = CellDocument.createElement("bind");
Attr matchFlag = CellDocument.createAttribute("match");
matchFlag.setNodeValue("dataRef");
bindNode.setAttributeNode(matchFlag);
Attr Boundpath = CellDocument.createAttribute("ref");
String realBindPath = null;
if( obj == null)
{
// means it is a table row
realBindPath = tablePath + "[*]";
}
else if( obj.isInTable())
{
System.out.println("Field: " + obj.getRelativePath() + " is in table");
if( checkIfinTableRow(node))
realBindPath = getRelativePath(obj);
else
{
realBindPath = obj.getPath();
}
}
else
realBindPath = obj.getPath();
System.out.println("Real Bound path: " + realBindPath);
Boundpath.setNodeValue(realBindPath);
bindNode.setAttributeNode(Boundpath);
node.appendChild(bindNode);
}
private String FormatSavePath(String path)
{
int index = path.lastIndexOf('.');
if( index != -1)
return path;
String newPath = path + ".xdp";
return newPath;
}
public String SaveAs(String path)
{
String formattedPath = FormatSavePath(path);
File newFile = new File(formattedPath);
if( newFile.exists())
return null;
try
{
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
DOMSource source = new DOMSource(doc);
File newXDPFile = new File(formattedPath);
StreamResult rs = new StreamResult(newXDPFile);
tf.transform(source,rs);
tf.reset();
}
catch(Exception e1)
{
e1.printStackTrace();
}
return path;
}
// currently can only match field by caption
private String FetchFieldCaption(Node item)
{
Node captionNode = Tool.getNodebyRoot("caption",item);
if( captionNode == null)
{
//System.out.println("Cannot find caption node within the field node");
return null;
}
Node valueNode = Tool.getNodebyRoot("value",captionNode);
if( valueNode == null)
{
//System.out.println("Cannot find value node within the caption node");
return null;
}
Node textNode = Tool.getNodebyRoot("text",valueNode);
if( textNode == null)
{
//System.out.println("Cannot find text node within the value node");
return null;
}
System.out.println("Caption Name: " + textNode.getTextContent());
return textNode.getTextContent();
}
public void LoadTemplateFile(String inputXDPName)
{
try
{
filecopy = new FileCopyFactory();
String OutputXMLFile = filecopy.copyFile(inputXDPName);
if (OutputXMLFile == null)
return;
InputStream inputXML = new FileInputStream(OutputXMLFile);
doc = dombuilder.parse(inputXML);
root = doc.getDocumentElement();
// but only template DOM is our concern...
filecopy.DeleteUnusedXML(OutputXMLFile);
}
catch (FileNotFoundException d)
{
d.printStackTrace();
}
catch (SAXException d)
{
d.printStackTrace();
System.exit(0);
}
catch (IOException d)
{
d.printStackTrace();
}
}
}
要获取更多Jerry的原创文章,请关注公众号"汪子熙":