使用具有非唯一标记路径的StAX解析XML,设计建议

时间:2013-10-14 14:25:20

标签: java xml parsing stax

我需要解析一个大的XML文件(可能会在Java中使用StAX)并将其输出到一个分隔的文本文件中,我有几个设计问题。这里首先是XML的一个例子

    <demographic>
        <value>001</value>
        <question>Name?</question>
        <value>Bob</value>
        <question>Last Name?</question>
        <value>Smith</value>
        <followUpQuestions>
            <question>Middle Init.</question>
            <value>J</value>
        </followUpQuestions>
    </demographic>

这需要输出(在分隔的输出文件中)

001~Bob~Smith~J

所以这是我的问题:

  1. 如何区分所有不同的“值”标签,因为标签名称不是唯一的。目前我尝试通过让“状态”变量在传递问题文本(例如“姓名?”)后打开来解决这个问题,但是这种方法对第一个值不起作用,因为我必须检查以确保'名称'并且'lastName'状态为关闭以确保我获得第一个值。

  2. 每当客户端更改问题的文本(发生)时,我必须更改代码并重新编译它。反正有没有避免这个?也许将问题文本保存在程序读入的文本文件中?

  3. 这可以扩展吗?我需要提取超过100个值,XML文件通常大约2 gig。

  4. 提前感谢您的帮助(来自Java和XML新手)!!

    更新:这是我尝试编写解决方案的代码,有人可以帮助简化吗?必须采用不那么混乱的方式:

    import javax.xml.stream.XMLInputFactory; 
    import javax.xml.stream.XMLStreamConstants; 
    import javax.xml.stream.XMLStreamException; 
    import javax.xml.stream.XMLStreamReader;
    import java.io.*;
    class TestJavaForStackOverflow{
    
    boolean nameState = false,
                    lastNameState = false,
                    middleInitState = false;
    
    String  name = "",
                    lastName = "",
                    middleInit = "",
                    value = "";
    
    public void parse() throws IOException, XMLStreamException{
            XMLInputFactory factory = XMLInputFactory.newInstance();
            XMLStreamReader streamReader = factory.createXMLStreamReader(
                    new FileReader("/n04/data/revmgmt/anthony/scripts/Java_Programs/TestJavaForStackOverflow.xml"));
    
    
    
            while(streamReader.hasNext()){
                    streamReader.next();
    
                    if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT){
                            if("demographic".equals(streamReader.getLocalName())){
                                    parseDemographicInformation(streamReader);
                            } 
                    }
            }
            System.out.println(value + "~" + name + "~" + lastName + "~" + middleInit);
    }
    
    public void parseDemographicInformation(XMLStreamReader streamReader) throws XMLStreamException {
            while(streamReader.hasNext()){
                    streamReader.next();
    
                    if(streamReader.getEventType() == XMLStreamReader.END_ELEMENT){
                            if("demographic".equals(streamReader.getLocalName())){
                                return;
                            }
                    } 
                    else if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT){
                         if("question".equals(streamReader.getLocalName())){
                            streamReader.next();
                            if("Name?".equals(streamReader.getText())){
                                nameState = true;
                            }
                            else if("Last Name?".equals(streamReader.getText())){
                                lastNameState = true;
                            }
                            else if("Middle Init.".equals(streamReader.getText())){
                                middleInitState = true;
                            }
                        }
                        else if("value".equals(streamReader.getLocalName())){
                            streamReader.next();
                            if(nameState){ 
                                name = streamReader.getText();
                                nameState = false;
                            }
                            else if (lastNameState){
                                lastName = streamReader.getText();
                                lastNameState = false;
                            }
                            else if (middleInitState){ 
                                middleInit = streamReader.getText();
                                middleInitState = false;
                            }
                            else {
                                value = streamReader.getText();
                            }
                        }
                    }
    
            }
    }
    public static void main(String[] args){
        TestJavaForStackOverflow t = new TestJavaForStackOverflow();
        try{t.parse();}
        catch(IOException e1){}
        catch(XMLStreamException e2){}
    }
    }
    

1 个答案:

答案 0 :(得分:0)

我认为如果你有很多不同的问题要解析,那么这些标志不是很可扩展的,并且保存结果的全局变量都不是......如果你有100个问题那么你需要100个变量,当它们会随着时间的推移而变化,这将使它们保持最新状态。我会使用一个map结构来保存结果,另一个用来保存每个问题文本和你想要捕获的相应字段之间的对应关系(这不是实际的Java,只是一个近似值):

public Map parseDemographicInformation(XmlStream xml, Map questionMap) {
  Map record = new Map();
  String field = "id";
  while((elem = xml.getNextElement())) {
    if(elem.tagName == "question") {
      field = questionMap[elem.value];
    } else if(elem.tagName == "value") {
      record[field] = elem.value;
    }
  }
  return record;
}

然后你有这样的东西输出结果:

String[] fieldsToOutput = { "id", "firstName", "lastName" };  // ideally read this from a file too so it can be changed dynamically

// ...

for(int i=0; i < fieldsToOutput.length; i++){
  if(i > 0)
    System.out.print("~");
  System.out.print(record[fieldsToOutput[i]]);
}
System.out.println();