我有一个很大的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&um__1">
<Lemma partOfSpeech="n" writtenForm="تَوَاؤُم"/>
<Sense id="tawaA&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阅读器,因为内存消耗。但我不应该如何继续得到我想要的东西。请帮帮我。
答案 0 :(得分:1)
SAX Parser与DOM Parser不同。它只查看当前item
它未能看到的项目,直到它们成为当前item
。它是XML文件非常大时可以使用的众多功能之一。而不是那里有很多。仅举几例:
SAX
PARSER DOM
PARSER JDOM
PARSER DOM4J
PARSER STAX
PARSER 您可以找到所有教程here。
在我学习之后,我会直接使用DOM4J
或JDOM
作为商业产品。
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信息:
WordForm
表示XML文档中的任何<WordForm …>
元素。@
开头的名称代表属性。例如,@writtenForm
引用XML文档中的任何writtenForm=…
属性。LexicalEntry/Lemma
表示任何<Lemma>
元素,它是<LexicalEntry>
元素的直接子元素。 Synset/@id
表示任何id=…
元素的<Synset>
属性。/
开头的路径表示Unix中的绝对(根相对)路径一样,以斜杠开头的XPath表示相对于XML文档根目录的表达式。//LexicalEntry
表示文档中的任何LexicalEntry; /LexicalEntry
仅匹配作为根元素的LexicalEntry元素。Synset[@baseConcept='3']
将任何<Synset>
元素与baseConcept属性匹配,该属性的值为字符串&#34; 3&#34;。$
替换,如$word
。这些变量如何传递给XPath表达式取决于引擎。 Java使用setXPathVariableResolver方法。变量名称与节点名称位于完全独立的名称空间中,因此,如果变量名称与XML文档中的元素名称或属性名称相同,则无关紧要。因此,代码中的XPath表达式意味着:
//LexicalEntry[WordForm/@writtenForm=$word or Lemma/@writtenForm=$word]/Sense/@synset
将任何<LexicalEntry>
元素匹配到XML文档中具有
word
变量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
在外部定义。
逻辑上,上述内容应该是:
答案 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树的所有分支。