Java中的SGML解析器?
我正在寻找一个Java解析器,它可以解析SGML格式的文档。 对于重复监视器: 我知道另外两条讨论这个话题的线索: 但两者都没有解决方案,因此出现了新的话题 对于混淆XML和SGML的人: 请阅读: (简言之,有足够细微的差异,至少使其在普通形式下无法使用) 对于喜欢让海报在谷歌上搜索的人: 我已经做到了,我能想到的最接近的是广受欢迎的SAXParser: 但这当然是一个XML解析器。我四处看看是否有人实现了SAX解析器的修改以适应SGML 最后,我不能使用SX,因为我正在寻找Java解决方案Java中的SGML解析器?,java,sgml,Java,Sgml,我正在寻找一个Java解析器,它可以解析SGML格式的文档。 对于重复监视器: 我知道另外两条讨论这个话题的线索: 但两者都没有解决方案,因此出现了新的话题 对于混淆XML和SGML的人: 请阅读: (简言之,有足够细微的差异,至少使其在普通形式下无法使用) 对于喜欢让海报在谷歌上搜索的人: 我已经做到了,我能想到的最接近的是广受欢迎的SAXParser: 但这当然是一个XML解析器。我四处看看是否有人实现了SAX解析器的修改以适应SGML 最后,我不能使用SX,因为我正在寻找Java解决方案
谢谢!:) 我有几种解决这个问题的方法 第一个是您所做的——检查sgml文档是否与XML足够接近,以使标准SAX解析器能够工作 第二种方法是对HTML解析器执行同样的操作。这里的诀窍是找到一个不忽略非HTML元素的元素 在搜索“SGML解析器Java”时,我确实在acedemia中找到了一些Java SGML解析器。我不知道他们工作得有多好 最后一步是使用标准(非Java)SGML解析器,并将文档转换为可以用Java阅读的内容
看起来您能够完成第一步。目前没有使用Java解析SGML的api。也没有任何api或库用于将SGML转换为XML,然后使用Java对其进行解析。到目前为止,在我所从事的所有项目中,SGML的地位都被XML所取代,我认为在这方面不会有任何工作要做,但这只是一个猜测 是一所大学提供的开源代码,但是我还没有尝试过,你需要搜索其他相关类。我相信Java中唯一可行的解决方案需要正则表达式
此外,这里还有一个用于公共SGML/XML软件的示例。如果您正在解析它的HTML,这可能会:
JavaSE在
javax.swing.text.HTML.parser
包中包含一个HTML解析器。它在文档中声称是一个通用的SGML解析器,但在文档中反诉说您应该只在提供的HTMLDTD类中使用它
如果您将其置于宽松模式,并且您的SGML文档没有很多隐含的结束标记,那么您可能会得到合理的结果
在JavaDoc中阅读有关解析器的内容,如下所示:
创建一个如下所示的实例:
new DocumentParser(DTD.getDTD("html32"))
或者,您也可以忽略针对在DocumentParser中使用自定义DTD的警告,并创建与您自己的SGML格式规则相匹配的DTD子类
这显然不是一个工业级的SGML解析器,但它应该是一次性数据迁移工作的良好起点。我发现它在以前的项目中对解析HTML很有用。我通过JNI使用OpenSP,因为似乎没有纯Java SGML解析器。我已经编写了一个实验性的类似SAX的包装器,可以在上获得(当然,它有JNI的所有缺点……但足以满足我的需求)
另一种方法是使用sx-from将文档转换为XML,然后运行传统的SAX解析器。虽然这是一篇非常古老的文章,我并不认为我提供的答案是完美的,但它达到了我的目的。因此,我保留了我使用堆栈编写的代码,以便以我的案例所需的方式获取数据。我希望它能对其他人有所帮助
try (BufferedReader br = new BufferedReader(new FileReader(new File(
fileName)))) {
while ((line = br.readLine()) != null) {
line = line.trim();
int startOfTag = line.indexOf("<");
int endOfTag = line.indexOf(">");
String currentTag = "";
if (startOfTag > -1 && endOfTag > -1) {
if (countStart)
headerTagsCounter++;
currentTag = line.substring(startOfTag + 1, endOfTag);
String currentData = line.substring(endOfTag + 1,
line.length());
if (i == 1) {
tagStack.push(currentTag);
i++;
}
if (currentData.isEmpty() || currentData == "") {//If there is no data, its a parent tag...
if (!currentTag.contains("/")) {// if its an opening tag...
switch (currentTag) {// these tags are useless in my case, so just skipping these tags.
case "CORRECTION":
case "PAPER":
case "PRIVATE-TO-PUBLIC":
case "DELETION":
case "CONFIRMING-COPY":
case "CAPTION":
case "STUB":
case "COLUMN":
case "TABLE-FOOTNOTES-SECTION":
case "FOOTNOTES":
case "PAGE":
break;
default: {
countStart = false;
int tagCounterNumber = 0;
String historyTagToRemove = "";
for (String historyTag : historyStack) {
String tagCounter = "";
if (historyTag.contains(currentTag)) {//if it's a repeating tag..Append the counter and update the same in history tag..
historyTagToRemove = historyTag;
if (historyTag
.equalsIgnoreCase(currentTag)) {
tagCounterNumber = 1;
} else if (historyTag.length() > currentTag
.length()) {
tagCounter = historyTag
.substring(currentTag
.length());
if (tagCounter != null
&& !tagCounter.isEmpty()) {
tagCounterNumber = Integer
.parseInt(tagCounter) + 1;
}
}
}
}
if (tagCounterNumber > 0)
currentTag += tagCounterNumber;
if (historyTagToRemove != null
&& !historyTagToRemove.isEmpty()) {
historyStack.remove(historyTagToRemove);
historyStack.push(currentTag);
}
tagStack.push(currentTag);
break;
}
}
} else// if its end of a tag... Match the current tag with top of stack and if its a match, pop it out
{
currentTag = currentTag.substring(1);
String tagRemoved = "";
String topStackTag = tagStack.lastElement();
if (topStackTag.contains(currentTag)) {
tagRemoved = tagStack.pop();
historyStack.push(tagRemoved);
}
if (tagStack.size() < 2)
cik = "";
if (tagStack.size() == 2 && cik != null
&& !cik.isEmpty())
for (int j = headerTagsCounter - 1; j < tagList.size(); j++) {
String item = tagList.get(j);
if (!item.contains("@@")) {
item += "@@" + cik;
tagList.remove(j);
tagList.add(j, item);
}
}
}
} else {// if current tag has some data...
currentData = currentData.trim();
String stackValue = "";
for (String tag : tagStack) {
if (stackValue != null && !stackValue.isEmpty()
&& stackValue != "")
stackValue = stackValue + "||" + tag;
else
stackValue = tag;
}
switch (currentTag) {
case "ACCESSION-NUMBER":
accessionNumber = currentData;
break;
case "FILING-DATE":
dateFiled = currentData;
break;
case "TYPE":
formType = currentData;
break;
case "CIK":
cik = currentData;
break;
}
tagList.add(stackValue + "$$" + currentTag + "::"+ currentData);
}
}
}
// Now all your data is available with in tagList, stack is separated by ||, key is separated by $$ and value is separated by ::
}
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
人们还在使用SGML吗?我真的很好奇-在你的情况下它是用来做什么的?我有大约2500个文档是用SGML格式化的-我需要使用这些数据进行一些统计分析。我正在散列一个快速的程序来确定标签的分布,我浏览了其中的一些,他们似乎只使用了一些精选的标签。在这种情况下,我可以很容易地使用SAXParser。我有数以万计的SGML文件,并且一直在制作更多的文件。SGML在出版业中仍然得到了相当广泛的应用,尽管还不成熟!等等——最后一条评论说“我能够使用SAX解析器。”那么你找到了答案,不是吗?为什么不写一个答案并将其标记为已完成?是和否。我正在寻找一个SGML解析器——这是最初的目标。我使用SAX解析器只是一种解决方法,因为它适合我当前的文档集,而不是解决方案。我根本没有找到任何Java SGML解析器的资源-如果您再次找到它,如果您可以发布链接,那就太好了-谢谢!事实上,当我重新查看时,我也找不到任何东西。第一个链接已经过时了。
SEC-HEADER$$SEC-HEADER::0001193125-16-799070.hdr.sgml : 20161220
SEC-HEADER$$ACCEPTANCE-DATETIME::20161220172458
SEC-HEADER$$ACCESSION-NUMBER::0001193125-16-799070
SEC-HEADER$$TYPE::485APOS
SEC-HEADER$$PUBLIC-DOCUMENT-COUNT::9
SEC-HEADER$$FILING-DATE::20161220
SEC-HEADER$$DATE-OF-FILING-DATE-CHANGE::20161220
SEC-HEADER||FILER||COMPANY-DATA$$CONFORMED-NAME::ARTISAN PARTNERS FUNDS INC@@0000935015
SEC-HEADER||FILER||COMPANY-DATA$$CIK::0000935015@@0000935015
SEC-HEADER||FILER||COMPANY-DATA$$IRS-NUMBER::391811840@@0000935015
SEC-HEADER||FILER||COMPANY-DATA$$STATE-OF-INCORPORATION::WI@@0000935015
SEC-HEADER||FILER||COMPANY-DATA$$FISCAL-YEAR-END::0930@@0000935015
SEC-HEADER||FILER||FILING-VALUES$$FORM-TYPE::485APOS@@0000935015
SEC-HEADER||FILER||FILING-VALUES$$ACT::33@@0000935015
SEC-HEADER||FILER||FILING-VALUES$$FILE-NUMBER::033-88316@@0000935015
SEC-HEADER||FILER||FILING-VALUES$$FILM-NUMBER::162062197@@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$STREET1::875 EAST WISCONSIN AVE STE 800@@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$CITY::MILWAUKEE@@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$STATE::WI@@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$ZIP::53202@@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$PHONE::414-390-6100@@0000935015
SEC-HEADER||FILER||MAIL-ADDRESS$$STREET1::875 EAST WISCONSIN AVE STE 800@@0000935015
SEC-HEADER||FILER||MAIL-ADDRESS$$CITY::MILWAUKEE@@0000935015
SEC-HEADER||FILER||MAIL-ADDRESS$$STATE::WI@@0000935015
SEC-HEADER||FILER||MAIL-ADDRESS$$ZIP::53202@@0000935015
SEC-HEADER||FILER||FORMER-COMPANY$$FORMER-CONFORMED-NAME::ARTISAN FUNDS INC@@0000935015
SEC-HEADER||FILER||FORMER-COMPANY$$DATE-CHANGED::19950310@@0000935015
SEC-HEADER||FILER||FORMER-COMPANY1$$FORMER-CONFORMED-NAME::ZIEGLER FUNDS INC@@0000935015
SEC-HEADER||FILER||FORMER-COMPANY1$$DATE-CHANGED::19950109@@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$CONFORMED-NAME::ARTISAN PARTNERS FUNDS INC@@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$CIK::0000935015@@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$IRS-NUMBER::391811840@@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$STATE-OF-INCORPORATION::WI@@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$FISCAL-YEAR-END::0930@@0000935015
SEC-HEADER||FILER1||FILING-VALUES1$$FORM-TYPE::485APOS@@0000935015
SEC-HEADER||FILER1||FILING-VALUES1$$ACT::40@@0000935015
SEC-HEADER||FILER1||FILING-VALUES1$$FILE-NUMBER::811-08932@@0000935015
SEC-HEADER||FILER1||FILING-VALUES1$$FILM-NUMBER::162062198@@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$STREET1::875 EAST WISCONSIN AVE STE 800@@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$CITY::MILWAUKEE@@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$STATE::WI@@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$ZIP::53202@@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$PHONE::414-390-6100@@0000935015
SEC-HEADER||FILER1||MAIL-ADDRESS1$$STREET1::875 EAST WISCONSIN AVE STE 800@@0000935015
SEC-HEADER||FILER1||MAIL-ADDRESS1$$CITY::MILWAUKEE@@0000935015
SEC-HEADER||FILER1||MAIL-ADDRESS1$$STATE::WI@@0000935015
SEC-HEADER||FILER1||MAIL-ADDRESS1$$ZIP::53202@@0000935015
SEC-HEADER||FILER1||FORMER-COMPANY2$$FORMER-CONFORMED-NAME::ARTISAN FUNDS INC@@0000935015
SEC-HEADER||FILER1||FORMER-COMPANY2$$DATE-CHANGED::19950310@@0000935015
SEC-HEADER||FILER1||FORMER-COMPANY3$$FORMER-CONFORMED-NAME::ZIEGLER FUNDS INC@@0000935015
SEC-HEADER||FILER1||FORMER-COMPANY3$$DATE-CHANGED::19950109@@0000935015
SEC-HEADER||SERIES-AND-CLASSES-CONTRACTS-DATA||NEW-SERIES-AND-CLASSES-CONTRACTS$$OWNER-CIK::0000935015
SEC-HEADER||SERIES-AND-CLASSES-CONTRACTS-DATA||NEW-SERIES-AND-CLASSES-CONTRACTS||NEW-SERIES$$SERIES-ID::S000056665
SEC-HEADER||SERIES-AND-CLASSES-CONTRACTS-DATA||NEW-SERIES-AND-CLASSES-CONTRACTS||NEW-SERIES$$SERIES-NAME::Artisan Thematic Fund
SEC-HEADER||SERIES-AND-CLASSES-CONTRACTS-DATA||NEW-SERIES-AND-CLASSES-CONTRACTS||NEW-SERIES||CLASS-CONTRACT$$CLASS-CONTRACT-ID::C000179292
SEC-HEADER||SERIES-AND-CLASSES-CONTRACTS-DATA||NEW-SERIES-AND-CLASSES-CONTRACTS||NEW-SERIES||CLASS-CONTRACT$$CLASS-CONTRACT-NAME::Investor Shares