解,而無需使用外部包,或甚至的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