Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用SAX解析器解析大型XML文件时,类变得臃肿且无法读取-如何修复此问题?_Java_Saxparser_Code Readability - Fatal编程技术网

Java 使用SAX解析器解析大型XML文件时,类变得臃肿且无法读取-如何修复此问题?

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

这纯粹是一个与代码可读性相关的问题,类的性能不是问题

下面是我如何构建这个XMLHandler的:

对于与应用程序相关的每个元素,“ElementName”中都有一个布尔值,我根据解析过程中的位置将其设置为true或false:问题是,我现在在类的开头有10+个布尔值声明,它越来越大

在我的startElement和endElement方法中,我有数百行

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>