如何获取XML文件的特定信息

时间:2016-12-22 14:51:44

标签: java parsing xlm

我有一个很大的XML文件,下面是它的摘录:

...
<LexicalEntry id="Ait~ifAq_1">
  <Lemma partOfSpeech="n" writtenForm="اِتِّفاق"/>
  <Sense id="Ait~ifAq_1_tawaAfuq_n1AR" synset="tawaAfuq_n1AR"/>
  <WordForm formType="root" writtenForm="وفق"/>
</LexicalEntry>
<LexicalEntry id="tawaA&amp;um__1">
  <Lemma partOfSpeech="n" writtenForm="تَوَاؤُم"/>
  <Sense id="tawaA&amp;um__1_AinosijaAm_n1AR" synset="AinosijaAm_n1AR"/>
  <WordForm formType="root" writtenForm="وأم"/>
</LexicalEntry>    
<LexicalEntry id="tanaAgum_2">
  <Lemma partOfSpeech="n" writtenForm="تناغُم"/>
  <Sense id="tanaAgum_2_AinosijaAm_n1AR" synset="AinosijaAm_n1AR"/>
  <WordForm formType="root" writtenForm="نغم"/>
</LexicalEntry>


<Synset baseConcept="3" id="tawaAfuq_n1AR">
  <SynsetRelations>
    <SynsetRelation relType="hyponym" targets="AinosijaAm_n1AR"/>
    <SynsetRelation relType="hyponym" targets="AinosijaAm_n1AR"/>
    <SynsetRelation relType="hypernym" targets="ext_noun_NP_420"/>
  </SynsetRelations>
  <MonolingualExternalRefs>
    <MonolingualExternalRef externalReference="13971065-n" externalSystem="PWN30"/>
  </MonolingualExternalRefs>
</Synset>
...

我想从中提取具体信息。对于来自writtenForm<Lemma>的给定<WordForm>,该计划从synset的{​​{1}}获取<Sense>的值(相同{{ 1}})并搜索与writtenForm<LexicalEntry>具有相同值的id的所有值<Synset>。之后,该程序为我们提供synset的所有关系,即它显示<Sense>的值并返回Synset并查找relType的值<LexicalEntry> 1}}具有相同synset值的人会显示其<Sense>

我认为这有点复杂,但结果应该是这样的:

targets

其中一个解决方案是使用Stream阅读器,因为内存消耗。但我不应该如何继续得到我想要的东西。请帮帮我。

3 个答案:

答案 0 :(得分:1)

SAX Parser与DOM Parser不同。它只查看当前item它未能看到的项目,直到它们成为当前item。它是XML文件非常大时可以使用的众多功能之一。而不是那里有很多。仅举几例:

  • SAX PARSER
  • DOM PARSER
  • JDOM PARSER
  • DOM4J PARSER
  • STAX PARSER

您可以找到所有教程here

在我学习之后,我会直接使用DOM4JJDOM作为商业产品。

SAX Parser的逻辑是你有一个MyHandler类正在扩展DefaultHandler@Overrides一些方法:

XML 文件:

<?xml version="1.0"?>
<class>
   <student rollno="393">
      <firstname>dinkar</firstname>
      <lastname>kad</lastname>
      <nickname>dinkar</nickname>
      <marks>85</marks>
   </student>
   <student rollno="493">
      <firstname>Vaneet</firstname>
      <lastname>Gupta</lastname>
      <nickname>vinni</nickname>
      <marks>95</marks>
   </student>
   <student rollno="593">
      <firstname>jasvir</firstname>
      <lastname>singn</lastname>
      <nickname>jazz</nickname>
      <marks>90</marks>
   </student>
</class>

处理程序类:

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class UserHandler extends DefaultHandler {

   boolean bFirstName = false;
   boolean bLastName = false;
   boolean bNickName = false;
   boolean bMarks = false;

   @Override
   public void startElement(String uri, 
   String localName, String qName, Attributes attributes)
      throws SAXException {
      if (qName.equalsIgnoreCase("student")) {
         String rollNo = attributes.getValue("rollno");
         System.out.println("Roll No : " + rollNo);
      } else if (qName.equalsIgnoreCase("firstname")) {
         bFirstName = true;
      } else if (qName.equalsIgnoreCase("lastname")) {
         bLastName = true;
      } else if (qName.equalsIgnoreCase("nickname")) {
         bNickName = true;
      }
      else if (qName.equalsIgnoreCase("marks")) {
         bMarks = true;
      }
   }

   @Override
   public void endElement(String uri, 
   String localName, String qName) throws SAXException {
      if (qName.equalsIgnoreCase("student")) {
         System.out.println("End Element :" + qName);
      }
   }

   @Override
   public void characters(char ch[], 
      int start, int length) throws SAXException {
      if (bFirstName) {
         System.out.println("First Name: " 
            + new String(ch, start, length));
         bFirstName = false;
      } else if (bLastName) {
         System.out.println("Last Name: " 
            + new String(ch, start, length));
         bLastName = false;
      } else if (bNickName) {
         System.out.println("Nick Name: " 
            + new String(ch, start, length));
         bNickName = false;
      } else if (bMarks) {
         System.out.println("Marks: " 
            + new String(ch, start, length));
         bMarks = false;
      }
   }
}

主要类:

import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SAXParserDemo {
   public static void main(String[] args){

      try { 
         File inputFile = new File("input.txt");
         SAXParserFactory factory = SAXParserFactory.newInstance();
         SAXParser saxParser = factory.newSAXParser();
         UserHandler userhandler = new UserHandler();
         saxParser.parse(inputFile, userhandler);     
      } catch (Exception e) {
         e.printStackTrace();
      }
   }   
}

答案 1 :(得分:1)

XPath就是为此而设计的。 Java在javax.xml.xpath包中提供了对它的支持。

要做你想做的事,代码看起来像这样:

List<String> findRelations(String word,
                           Path xmlFile)
throws XPathException {

    String xmlLocation = xmlFile.toUri().toASCIIString();

    XPath xpath = XPathFactory.newInstance().newXPath();

    xpath.setXPathVariableResolver(
        name -> (name.getLocalPart().equals("word") ? word : null));
    String id = xpath.evaluate(
        "//LexicalEntry[WordForm/@writtenForm=$word or Lemma/@writtenForm=$word]/Sense/@synset",
        new InputSource(xmlLocation));

    xpath.setXPathVariableResolver(
        name -> (name.getLocalPart().equals("id") ? id : null));
    NodeList matches = (NodeList) xpath.evaluate(
        "//Synset[@id=$id]/SynsetRelations/SynsetRelation",
        new InputSource(xmlLocation),
        XPathConstants.NODESET);

    List<String> relations = new ArrayList<>();

    int matchCount = matches.getLength();
    for (int i = 0; i < matchCount; i++) {
        Element match = (Element) matches.item(i);

        String relType = match.getAttribute("relType");
        String synset = match.getAttribute("targets");

        xpath.setXPathVariableResolver(
            name -> (name.getLocalPart().equals("synset") ? synset : null));
        NodeList formNodes = (NodeList) xpath.evaluate(
            "//LexicalEntry[Sense/@synset=$synset]/WordForm/@writtenForm",
            new InputSource(xmlLocation),
            XPathConstants.NODESET);

        int formCount = formNodes.getLength();
        StringJoiner forms = new StringJoiner(",");
        for (int j = 0; j < formCount; j++) {
            forms.add(
                formNodes.item(j).getNodeValue());
        }

        relations.add(
            String.format("%s %s %s", word, relType, forms));
    }

    return relations;
}

一些基本的XPath信息:

  • XPath使用单个类似文件路径的字符串来匹配XML文档的各个部分。这些部分可以是文档的任何结构部分:文本,元素,属性,甚至是注释等内容。
  • Java XPath表达式可以尝试仅匹配一个部分或几个部分,或甚至可以将所有匹配的部分连接为String。
  • 在XPath表达式中,名称本身表示一个元素。例如,XPath中的WordForm表示XML文档中的任何<WordForm …>元素。
  • @开头的名称代表属性。例如,@writtenForm引用XML文档中的任何writtenForm=…属性。
  • 斜杠表示XML文档中的父级和子级。 LexicalEntry/Lemma表示任何<Lemma>元素,它是<LexicalEntry>元素的直接子元素。 Synset/@id表示任何id=…元素的<Synset>属性。
  • 正如以/开头的路径表示Unix中的绝对(根相对)路径一样,以斜杠开头的XPath表示相对于XML文档根目录的表达式。
  • 两个斜线表示一个后代,可能是直接子,孙子,曾孙等。因此,//LexicalEntry表示文档中的任何LexicalEntry; /LexicalEntry仅匹配作为根元素的LexicalEntry元素。
  • 方括号表示匹配限定符。 Synset[@baseConcept='3']将任何<Synset>元素与baseConcept属性匹配,该属性的值为字符串&#34; 3&#34;。
  • XPath可以引用外部定义的变量,使用类似Unix {shell}的$替换,如$word。这些变量如何传递给XPath表达式取决于引擎。 Java使用setXPathVariableResolver方法。变量名称与节点名称位于完全独立的名称空间中,因此,如果变量名称与XML文档中的元素名称或属性名称相同,则无关紧要。

因此,代码中的XPath表达式意味着:

//LexicalEntry[WordForm/@writtenForm=$word or Lemma/@writtenForm=$word]/Sense/@synset

将任何<LexicalEntry>元素匹配到XML文档中具有

的任何位置
  • 具有writForm属性的WordForm子项,其值等于word变量
  • 具有writForm属性的Lemma子项,其值等于word变量

并且对于每个此类<LexicalEntry>元素,返回synset元素的<Sense>元素的值,该元素是<LexicalEntry>元素的直接子元素。

在评估XPath表达式之前,word变量由xpath.setXPathVariableResolver在外部定义。

//Synset[@id=$id]/SynsetRelations/SynsetRelation

<Synset>属性等于id变量的XML文档中的任何位置匹配任何id元素。对于每个此类<Synset>元素,查找任何直接的SynsetRelations子元素,并返回其每个直接的SynsetRelation子元素。

在评估XPath表达式之前,id变量由xpath.setXPathVariableResolver在外部定义。

//LexicalEntry[Sense/@synset=$synset]/WordForm/@writtenForm

在XML文档中的任何位置匹配任何<LexicalEntry>元素,该元素具有<Sense>子元素,该元素具有synset属性,其值与synset变量相同。对于每个匹配的元素,找到任何<WordForm>子元素并返回该元素的writtenForm属性。

在评估XPath表达式之前,synset变量由xpath.setXPathVariableResolver在外部定义。

逻辑上,上述内容应该是:

  • 找到所请求单词的synset值。
  • 使用synset值查找SynsetRelation元素。
  • 找到与每个匹配的SynsetRelation的目标值对应的writtenForm值。

答案 2 :(得分:0)

如果此XML文件太大而无法在内存中表示,请使用SAX。

您需要编写SAX解析器以维护位置。为此,我通常使用StringBuffer,但Stack of Strings可以很好地工作。这一部分非常重要,因为它可以让您跟踪返回文档根目录的路径,这样您就可以了解文档在给定时间点的位置(在尝试仅提取时信息很少)。

主要逻辑流程如下:

 1. When entering a node, add the node's name to the stack.
 2. When exiting a node, pop the node's name (top element) off the stack.
 3. To know your location, read your current branch of the XML from the bottom of the stack to the top of the stack.
 4. When entering a region you care about, clear the buffer you will capture the characters into
 5. When exiting a region you care about, flush the buffer into the data structure you will return back as your output.

通过这种方式,您可以有效地跳过您不关心的XML树的所有分支。