Java 使用SAX解析器解析大型XML文件时,类变得臃肿且无法读取-如何修复此问题?
这纯粹是一个与代码可读性相关的问题,类的性能不是问题 下面是我如何构建这个XMLHandler的: 对于与应用程序相关的每个元素,“ElementName”中都有一个布尔值,我根据解析过程中的位置将其设置为true或false:问题是,我现在在类的开头有10+个布尔值声明,它越来越大 在我的startElement和endElement方法中,我有数百行Java 使用SAX解析器解析大型XML文件时,类变得臃肿且无法读取-如何修复此问题?,java,saxparser,code-readability,Java,Saxparser,Code Readability,这纯粹是一个与代码可读性相关的问题,类的性能不是问题 下面是我如何构建这个XMLHandler的: 对于与应用程序相关的每个元素,“ElementName”中都有一个布尔值,我根据解析过程中的位置将其设置为true或false:问题是,我现在在类的开头有10+个布尔值声明,它越来越大 在我的startElement和endElement方法中,我有数百行 if (qName = "elementName") { ... } else if (qName = "anotherElementN
if (qName = "elementName") {
...
} else if (qName = "anotherElementName") {
...
}
使用不同的解析规则(如果我在xml文件中处于此位置,请执行此操作,否则,请执行此操作,等等)
编写新的解析规则和调试变得越来越痛苦
编码sax解析器的最佳实践是什么?我可以做些什么来提高代码的可读性?这取决于XML结构。如果不同情况下的操作简单或(或多或少)“独立”,则可以尝试使用映射:
interface Command {
public void assemble(Attributes attr, MyStructure myStructure);
}
...
Map<String, Command> commands= new HashMap<String, Command>();
...
if(commands.contains(qName)) {
commands.get(qname).assemble(attr, myStructur);
} else {
//unknown qName
}
接口命令{
公共空集合(属性attr、MyStructure、MyStructure);
}
...
Map commands=newhashmap();
...
if(commands.contains(qName)){
commands.get(qname).assemble(attr,myStructur);
}否则{
//未知qName
}
我会退回到JAXB或类似的东西,让框架来完成工作。您使用布尔变量的目的是什么?跟踪筑巢情况
我最近通过对每个元素使用枚举实现了这一点。
代码正在运行,但这是我脑海中对它的粗略估计:
enum Element {
// special markers:
ROOT,
DONT_CARE,
// Element tag parents
RootElement( "root" ROOT),
AnElement( "anelement"), // DONT_CARE
AnotherElement( "anotherelement"),// DONT_CARE
AChild( "child", AnElement),
AnotherChild( "child", AnotherElement);
Element() {...}
Element(String tag, Element ... parents) {...}
}
class MySaxParser extends DefaultHandler {
Map<Pair<Element, String>, Element> elementMap = buildElementMap();
LinkedList<Element> nestingStack = new LinkedList<Element>();
public void startElement(String namespaceURI, String sName, String qName, Attributes attrs) {
Element parent = nestingStack.isEmpty() ? ROOT : nestingStack.lastElement();
Element element = elementMap.get(pair(parent, sName));
if (element == null)
element = elementMap.get(DONT_CARE, sName);
if (element == null)
throw new IllegalStateException("I did not expect <" + sName + "> in this context");
nestingStack.addLast(element);
switch (element) {
case RootElement: ... // Probably don't need cases for many elements at start unless we have attributes
case AnElement: ...
case AnotherElement: ...
case AChild: ...
case AnotherChild: ...
default: // Most cases here. Generally nothing to do on startElement
}
}
public void endElement(String namespaceURI, String sName, String qName) {
// Similar to startElement() but most switch cases do something with the data.
Element element = nestingStack.removeLast();
if (!element.tag.equals(sName)) throw IllegalStateException();
switch (element) {
...
}
}
// Construct the structure map from the parent information.
private Map<Pair<Element, String>, Element> buildElementMap() {
Map<Pair<Element, String>, Element> result = new LinkedHashMap<Pair<Element, String>, Element>();
for (Element element: Element.values()) {
if (element.tag == null) continue;
if (element.parents.length == 0)
result.put(pair(DONT_CARE, element.tag), element);
else for (Element parent: element.parents) {
result.put(pair(parent, element.tag), element);
}
}
return result;
}
// Convenience method to avoid the need for using "new Pair()" with verbose Type parameters
private <A,B> Pair<A,B> pair(A a, B b) {
return new Pair<A, B>(a, b);
}
// A simple Pair class, just for completeness. Better to use an existing implementation.
private static class Pair<A,B> {
final A a;
final B b;
Pair(A a, B b){ this.a = a; this.b = b;}
public boolean equals(Object o) {...};
public int hashCode() {...};
}
}
使用这种技术,我们不需要使用标志来跟踪上下文,以便知道正在处理哪个
元素。上下文被声明为元素
枚举定义的一部分,并通过消除各种状态变量来减少混淆。因此,如果我遵循这一权利,我必须为每个qName实现不同的组装方法?这确实会将if/else语句的列表减少到6行,但我真的不知道如何对每个命令执行不同的操作,例如,很难说这种样式是否比if-else级联更好。这完全取决于你在任何情况下需要做什么。如果构建一个大对象或必须切换某些设置,则贴图样式可能更好。如果案例之间存在复杂的交互,或者需要大量的中间数据结构,那么可能会变得太混乱。出于好奇,您选择使用SAX而不是DOM解析器有什么原因吗。文件大小>几个100KB吗?我只想知道b/c对于足够小的文件来说,任何性能的提高都几乎可以忽略不计。xml-to-java绑定解决方案也是如此,正如一些评论所提到的,xml的行长在30k(2000KB)到100k(5000KB)之间。上帝保佑XML-你能说得更具体些吗?我对JAXB了解不多,它是和SAX一样高效还是比SAX更高效?这将如何解决我的问题?如果我理解正确,我只需要为映射创建一个模式,然后让JAXB执行所有解析?使用JAXB从该模式创建Java DOM,然后使用它将文档解析为DOM实例。在内部,它使用SAX进行解析,因此在性能方面应该大致相同。但是,在解析结束时,您将得到一个内存中的对象树,因此取决于您之前实际执行的操作,最终可能需要更多内存。这可能是一个问题,因为文档越大,需要的内存就越多。我知道使用链接映射来跟踪我在XML文件中的位置,但这对映射的目的是什么?@SAKIROGLU Koray:这对映射只是一个两值映射键的持有者。我编辑了我的答案来澄清这一点。
<root>
<anelement>
<child>Data pertaining to child of anelement</child>
</anelement>
<anotherelement>
<child>Data pertaining to child of anotherelement</child>
</anotherelement>
</root>