【问题标题】:stax xml confusion with getname functionstax xml 与 getname 函数混淆
【发布时间】:2025-12-21 02:25:12
【问题描述】:

我有一个这样的 xml 文件:

<comment type="PTM">
    <text evidence="19">Sumoylated following its interaction with PIAS1 and UBE2I.</text>
</comment>
<comment type="PTM">
    <text evidence="17">Ubiquitinated, leading to proteasomal degradation.</text>
</comment>
<comment type="disease">
    <text>A chromosomal aberration involving ZMYND11 is a cause of acute poorly differentiated myeloid leukemia. Translocation (10;17)(p15;q21) with MBTD1.</text>
</comment>
<comment type="disease" evidence="23">
    <disease id="DI-04257">
        <name>Mental retardation, autosomal dominant 30</name>
        <acronym>MRD30</acronym>
        <description>A disorder characterized by significantly below average general intellectual functioning associated with impairments in adaptive behavior and manifested during the developmental period. MRD30 patients manifest mild intellectual disability and subtle facial dysmorphisms, including hypertelorism, ptosis, and a wide mouth.</description>
        <dbReference type="MIM" id="616083"/>
    </disease>
    <text>The disease is caused by mutations affecting the gene represented in this entry.</text>
</comment>
<comment type="similarity">
    <text evidence="8">Contains 1 bromo domain.</text>
</comment>
<comment type="similarity">
    <text evidence="9">Contains 1 MYND-type zinc finger.</text>
</comment>

我使用 stax 来提取疾病信息。这是我的代码的一部分:

XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader eventReader = factory.createXMLEventReader( new FileReader(p)); 

            while(eventReader.hasNext()){
               XMLEvent event = eventReader.nextEvent();
               switch(event.getEventType()){
                  case XMLStreamConstants.START_ELEMENT:
                     StartElement startElement = event.asStartElement();
                     String qName = startElement.getName().getLocalPart();
                     if (qName.equalsIgnoreCase("comment")) {
                        System.out.println("Start Element : comment");
                        Iterator<Attribute> attributes = startElement.getAttributes();
                        Attribute a = attributes.next(); 
                         System.out.println("ATRIBUTES " + a.getName());
                        type = a.getValue();
                        System.out.println("Roll No : " + type);
                     }  else if(qName.equalsIgnoreCase("text") && type.equals("disease")){ text = true; } 

                     break;

                    case XMLStreamConstants.CHARACTERS:
                     Characters characters = event.asCharacters();
                     if(text){ res = res + " " + characters.getData(); 
                        //System.out.println("TEXT: " + res);
                        text = false;
                     }
                    break;

                  case  XMLStreamConstants.END_ELEMENT:
                     EndElement endElement = event.asEndElement();
                     if(endElement.getName().getLocalPart().equalsIgnoreCase("comment")){
                        //System.out.println("End Element : comment"); 
                        //System.out.println();
                     }
                     break; 

对于这种类型的线:

<comment type="disease">

我可以正确提取信息,但是当我尝试在此行中查找注释类型“疾病”时:

<comment type="disease" evidence="23">

它给了我 type=evidence 而不是 type=disease 应该的。因此,它不会从这种行中保存任何内容。

【问题讨论】:

  • 您会考虑使用非税基的答案吗?
  • 是的,我愿意。如果我想使用 STAX,我做了很多代码。

标签: java xml stax


【解决方案1】:

首先我们能否养成使用有用变量名的习惯,你有以下变量及其类型:a(node), text(boolean), qName(String).. . 这些变量让我摸不着头脑,想知道它们是什么:

a - 只是不是一个有用的名称,它实际上应该类似于 typeAttr 或者注意到它应该是 type="" 属性

text - 它是一个布尔值?!也许collectText 会更合适,因为它指定您应该收集下一个文本事件值。

qName - 它是一个字符串,它是 QName 的 localPart,如果它不是 QName,则不要将其命名为一个..


但你明白了,这已经足够了。您的问题在于您获得属性的位置。在 XML 中,属性没有特定的顺序,并且不会也不应该期望按照它们定义的顺序返回。在您的代码中,您有以下内容

Iterator<Attribute> attributes = startElement.getAttributes();
Attribute a = attributes.next(); 
System.out.println("ATRIBUTES " + a.getName());
type = a.getValue();

在这里,您从元素中获取第一个属性并将类型设置为等于其值。正如我所提到的,XML 属性没有特定的顺序,因此您将获得 evidence 属性。您应该按名称获取属性:

Attribute a = startElement.getAttributeByName(QName.valueOf("type"));
System.out.println("ATRIBUTES " + a.getName());
type = a.getValue();

【讨论】:

    【解决方案2】:

    抱歉,没有直接答案,而是对如何有效使用 StaX 或 XmlPull 发表评论:流式 XML 解析器旨在对递归下降解析友好(避免显式状态建模,这是您通常需要使用 SAX 解析器的东西)-在您的情况下,我希望使用以下方法(拒绝或忽略所有意外内容):

    Comment parseComment(XMLEventReader eventReader) {
       // call parseText and parseDisease for the corresponding element starts
    }
    
    Text parseText(XMLEventReader eventReader) {
    }
    
    Disease parseDisease(XmlEventReader eventReader) {
    } 
    

    也就是说,有一个权衡:如果您不需要流方面(性能),您最好只解析为 DOM,然后根据需要通过步行或窥视 DOM 来提取信息,完全避免使用低级别的 XML API。

    【讨论】:

      【解决方案3】:

      通过使用 Stax,我假设您正在处理大型文档或资源有限的平台……事实上,内存开销主要是与 DOM 相关的问题。另一方面,VTD-XML 比 DOM 高效得多,同时保留了 DOM 编码风格的所有优点......请阅读这篇最新研究论文了解更多信息

      http://sdiwc.us/digitlib/journal_paper.php?paper=00000582.pdf

      import com.ximpleware.*;
      public class queryAttr {
          public static void main(String[] s) throws VTDException{
              VTDGen vg = new VTDGen();
              vg.selectLcDepth(5);// improve XPath performance for deep document
              if (!vg.parseFile("input.xml", false))
                  return;
              VTDNav vn = vg.getNav();
              AutoPilot ap = new AutoPilot(vn);
              ap.selectXPath("/root/comment[@type='disease' and @evidence='23']");
              int i=0,j=0;
              while((i=ap.evalXPath())!=-1){
                  if (vn.toElement(VTDNav.FIRST_CHILD)){
                      System.out.println(" element name: "+ vn.toString(vn.getCurrentIndex()));
                      j=vn.getText();
                      if (i!=-1)
                          System.out.println(""+vn.toString(i));
                      if (vn.toElement(VTDNav.NS)){
                          System.out.println(" element name: "+ vn.toString(vn.getCurrentIndex()));
                          j=vn.getText();
                          if (i!=-1)
                              System.out.println("text node==>"+vn.toString(i));
                      }
                      if (vn.toElement(VTDNav.NS)){
                          System.out.println(" element name: "+ vn.toString(vn.getCurrentIndex()));
                          j=vn.getText();
                          if (i!=-1)
                              System.out.println("text node==>"+vn.toString(i));
                      }
                      if (vn.toElement(VTDNav.NS)){
                          System.out.println(" element name: "+ vn.toString(vn.getCurrentIndex()));
                          j=vn.getText();
                          if (i!=-1)
                              System.out.println("text node==>"+vn.toString(i));
                      }
                      vn.toElement(VTDNav.PARENT);
                  }
      
              }
          }
      }
      

      【讨论】: