解,而无需使用外部包,或甚至的XPath:使用enum
“PARSE_MODE”,可能是在结合有Stack<PARSE_MODE>
:
1)碱性溶液:
一个)字段
private PARSE_MODE parseMode = PARSE_MODE.__UNDEFINED__;
// NB: essential that all these enum values are upper case, but this is the convention anyway
private enum PARSE_MODE {
__UNDEFINED__, ORDER, DATE, CUSTOMERID, ITEM };
private List<String> parseModeStrings = new ArrayList<String>();
private Stack<PARSE_MODE> modeBreadcrumbs = new Stack<PARSE_MODE>();
b)让你的List<String>
,也许在construc TOR:
for(PARSE_MODE pm : PARSE_MODE.values()){
// might want to check here that these are indeed upper case
parseModeStrings.add(pm.name());
}
C)startElement
和endElement
:
@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
String localNameUC = localName.toUpperCase();
// pushing "__UNDEFINED__" would mess things up! But unlikely name for an XML element
assert ! localNameUC.equals("__UNDEFINED__");
if(parseModeStrings.contains(localNameUC)){
parseMode = PARSE_MODE.valueOf(localNameUC);
// any "policing" to do with which modes are allowed to switch into
// other modes could be put here...
// in your case, go `new Order()` here when parseMode == ORDER
modeBreadcrumbs.push(parseMode);
}
else {
// typically ignore the start of this element...
}
}
@Override
private void endElement(String uri, String localName, String qName) throws Exception {
String localNameUC = localName.toUpperCase();
if(parseModeStrings.contains(localNameUC)){
// will not fail unless XML structure which is malformed in some way
// or coding error in use of the Stack, etc.:
assert modeBreadcrumbs.pop() == parseMode;
if(modeBreadcrumbs.empty()){
parseMode = PARSE_MODE.__UNDEFINED__;
}
else {
parseMode = modeBreadcrumbs.peek();
}
}
else {
// typically ignore the end of this element...
}
}
...所以这是什么意思呢?在任何时候,您都了解您所在的“解析模式”,并且您还可以查看Stack<PARSE_MODE> modeBreadcrumbs
,如果您需要了解您通过其他解析模式进入此处...
你characters
方法然后变成基本上清洁器:
public void characters(char[] ch, int start, int length) throws SAXException {
switch(parseMode){
case DATE:
// PS - this SimpleDateFormat object can be a field: it doesn't need to be created hundreds of times
SimpleDateFormat formatter. ...
String value = ...
...
break;
case CUSTOMERID:
order.setCustomerId(...
break;
case ITEM:
item = new Item();
// this next line probably won't be needed: when you get to endElement, if
// parseMode is ITEM, the previous mode will be restored automatically
// isItem = false ;
}
}
2)更“专业”溶液:
abstract
类的具体类必须延伸并且然后没有能力来修改Stack
等NB检查qName
而不是localName
。因此:
public abstract class AbstractSAXHandler extends DefaultHandler {
protected enum PARSE_MODE implements SAXHandlerParseMode {
__UNDEFINED__
};
// abstract: the concrete subclasses must populate...
abstract protected Collection<Enum<?>> getPossibleModes();
//
private Stack<SAXHandlerParseMode> modeBreadcrumbs = new Stack<SAXHandlerParseMode>();
private Collection<Enum<?>> possibleModes;
private Map<String, Enum<?>> nameToEnumMap;
private Map<String, Enum<?>> getNameToEnumMap(){
// lazy creation and population of map
if(nameToEnumMap == null){
if(possibleModes == null){
possibleModes = getPossibleModes();
}
nameToEnumMap = new HashMap<String, Enum<?>>();
for(Enum<?> possibleMode : possibleModes){
nameToEnumMap.put(possibleMode.name(), possibleMode);
}
}
return nameToEnumMap;
}
protected boolean isLegitimateModeName(String name){
return getNameToEnumMap().containsKey(name);
}
protected SAXHandlerParseMode getParseMode() {
return modeBreadcrumbs.isEmpty()? PARSE_MODE.__UNDEFINED__ : modeBreadcrumbs.peek();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
try {
_startElement(uri, localName, qName, attributes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// override in subclasses (NB I think caught Exceptions are not a brilliant design choice in Java)
protected void _startElement(String uri, String localName, String qName, Attributes attributes)
throws Exception {
String qNameUC = qName.toUpperCase();
// very undesirable ever to push "UNDEFINED"! But unlikely name for an XML element
assert !qNameUC.equals("__UNDEFINED__") : "Encountered XML element with qName \"__UNDEFINED__\"!";
if(getNameToEnumMap().containsKey(qNameUC)){
Enum<?> newMode = getNameToEnumMap().get(qNameUC);
modeBreadcrumbs.push((SAXHandlerParseMode)newMode);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
try {
_endElement(uri, localName, qName);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// override in subclasses
protected void _endElement(String uri, String localName, String qName) throws Exception {
String qNameUC = qName.toUpperCase();
if(getNameToEnumMap().containsKey(qNameUC)){
modeBreadcrumbs.pop();
}
}
public List<?> showModeBreadcrumbs(){
return org.apache.commons.collections4.ListUtils.unmodifiableList(modeBreadcrumbs);
}
}
interface SAXHandlerParseMode {
}
然后,具体子类的显着部分:
private enum PARSE_MODE implements SAXHandlerParseMode {
ORDER, DATE, CUSTOMERID, ITEM
};
private Collection<Enum<?>> possibleModes;
@Override
protected Collection<Enum<?>> getPossibleModes() {
// lazy initiation
if (possibleModes == null) {
List<SAXHandlerParseMode> parseModes = new ArrayList<SAXHandlerParseMode>(Arrays.asList(PARSE_MODE.values()));
possibleModes = new ArrayList<Enum<?>>();
for(SAXHandlerParseMode parseMode : parseModes){
possibleModes.add(PARSE_MODE.valueOf(parseMode.toString()));
}
// __UNDEFINED__ mode (from abstract superclass) must be added afterwards
possibleModes.add(AbstractSAXHandler.PARSE_MODE.__UNDEFINED__);
}
return possibleModes;
}
PS这是更复杂的东西起点:例如,您可以设置它保持与同步的List<Object>
Stack<PARSE_MODE>
:然后Objects
可以是你想要的任何东西,使你能够“回到”你正在处理的那个上升的“XML节点”。但不要使用Map
,但是:Stack
可能会不止一次包含相同的PARSE_MODE
对象。这实际上说明了所有的树状结构的基本特征:没有单独的节点(这里:解析模式)孤立存在的:其身份总是领先于它整个路径定义。
你可以试试StAX – 2013-03-25 23:33:04
如果你有一个生成XML的音乐会数据模型,我会看看XStream(http://xstream.codehaus.org/)。它将数据序列化到xml和后面做得非常好。 – 2013-03-25 23:43:49
关于主题,我喜欢从XSD开始并使用XmlBeans。稍微OT,XML标签应该是区分大小写的,这个代码打破了这一点。 – 2013-03-26 00:17:10