SGML-парсер в Java?
Я ищу парсер в Java, который может анализировать документ, отформатированный в SGML.
Для дублирующих мониторов:
Я знаю два других потока, которые обсуждают эту тему:
Разбор строки Java с SGML
Преобразование Java SGML в XML?
Но ни одна из них не имеет разрешения, следовательно, новая тема.
Для людей, которые смешивают XML с SGML:
Пожалуйста, прочтите следующее: http://www.w3.org/TR/NOTE-sgml-xml-971215#null
(короче говоря, есть достаточно тонких различий, чтобы хотя бы сделать его непригодным для использования в ванильной форме)
Для людей, которые любят просить плакаты в Google, он:
Я уже сделал это и самый близкий, с которым я мог придумать, был широко популярным SAXParser: http://download.oracle.com/javase/1.4.2/docs/api/javax/xml/parsers/SAXParser.html
Но это, конечно, предназначено для анализа XML. Я смотрю вокруг, чтобы увидеть, внедрил ли кто-нибудь модификацию SAX Parser для размещения SGML.
Наконец, я не могу использовать SX, поскольку я ищу решение Java.
Спасибо!:)
Ответы
Ответ 1
У меня есть несколько подходов к этой проблеме
Первое - это то, что вы сделали - проверьте, достаточно ли документа sgml достаточно для XML, чтобы стандартный анализатор SAX работал.
Во-вторых, делать то же самое с анализаторами HTML. Трюк здесь заключается в том, чтобы найти тот, который не игнорирует не-HTML-элементы.
Я нашел несколько синтаксисов Java SGML, больше в acedemia, при поиске "sgml parser Java". Я не знаю, насколько хорошо они работают.
Последний шаг - принять стандартный (не Java) синтаксический анализатор SGML и преобразовать документы во что-то, что вы можете прочитать на Java.
Похоже, вы смогли работать с первым шагом.
Ответ 2
В настоящее время нет api для синтаксического анализа SGML с использованием Java. Там также нет каких-либо api или библиотеки для преобразования SGML в XML и последующего анализа его с помощью Java. Поскольку статус SGML вытесняется XML для всех проектов, над которыми я работал до сих пор, я не думаю, что в этой области будет любая работа, но это только предположение.
Здесь - это код с открытым кодом из университета, который это делает, однако я не пробовал, и вам придется искать найти другие зависимые классы. Я считаю, что единственное жизнеспособное решение на Java потребует регулярных выражений.
Кроме того, здесь приведена ссылка для общедоступного программного обеспечения SGML/XML.
Ответ 3
Java SE включает парсер HTML в пакете javax.swing.text.html.parser
. В своей документации он утверждает, что он является общим синтаксическим анализатором SGML, но затем встречает в документации, что вы должны использовать его только с предоставленным HTML DTD классом.
Если вы поместили его в режим снисхождения, и ваши документы SGML не имеют много подразумеваемых конечных тегов, вы можете получить разумные результаты.
Читайте о парсере в своем JavaDoc, здесь: http://docs.oracle.com/javase/6/docs/api/javax/swing/text/html/parser/DocumentParser.html
Создайте такой экземпляр:
new DocumentParser(DTD.getDTD("html32"))
Или вы можете игнорировать предупреждения против использования пользовательского DTD с DocumentParser и создать подкласс DTD, который соответствует правилам вашего собственного формата SGML.
Это явно не промышленный синтаксический анализатор SGML, но он должен стать хорошей отправной точкой для одноразовой миграции данных. Я нашел это полезным в предыдущих проектах для разбора HTML.
Ответ 4
Я использую OpenSP через JNI, поскольку, похоже, нет чистого синтаксического анализа Java SGML. Я написал экспериментальную SAX-подобную оболочку, доступную в http://sourceforge.net/projects/sasgml (конечно, у нее есть все недостатки JNI... но этого было достаточно для моих требований).
Другой подход заключается в преобразовании документа в XML с помощью sx из Open SP, а затем запустить традиционный синтаксический анализатор SAX.
Ответ 5
Если его HTML-код, который вы обрабатываете, это может сделать:
http://ccil.org/~cowan/XML/tagsoup/
Ответ 6
Хотя это очень старый пост, и я не утверждаю, что ответ, который я предоставляю, идеален, но он служил моей цели. Поэтому я сохраняю этот код, который я написал, используя стек, чтобы получить данные в пути, в моем случае. Я надеюсь, что это может быть полезно для других.
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 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
}
}
Выход:
Источник файла: http://10k-staging.s3.amazonaws.com/edgar0105/2016/12/20/935015/000119312516799070/0001193125-16-799070.hdr.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 [email protected]@0000935015
SEC-HEADER||FILER||COMPANY-DATA$$CIK::[email protected]@0000935015
SEC-HEADER||FILER||COMPANY-DATA$$IRS-NUMBER::[email protected]@0000935015
SEC-HEADER||FILER||COMPANY-DATA$$STATE-OF-INCORPORATION::[email protected]@0000935015
SEC-HEADER||FILER||COMPANY-DATA$$FISCAL-YEAR-END::[email protected]@0000935015
SEC-HEADER||FILER||FILING-VALUES$$FORM-TYPE::[email protected]@0000935015
SEC-HEADER||FILER||FILING-VALUES$$ACT::[email protected]@0000935015
SEC-HEADER||FILER||FILING-VALUES$$FILE-NUMBER::[email protected]@0000935015
SEC-HEADER||FILER||FILING-VALUES$$FILM-NUMBER::[email protected]@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$STREET1::875 EAST WISCONSIN AVE STE [email protected]@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$CITY::[email protected]@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$STATE::[email protected]@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$ZIP::[email protected]@0000935015
SEC-HEADER||FILER||BUSINESS-ADDRESS$$PHONE::[email protected]@0000935015
SEC-HEADER||FILER||MAIL-ADDRESS$$STREET1::875 EAST WISCONSIN AVE STE [email protected]@0000935015
SEC-HEADER||FILER||MAIL-ADDRESS$$CITY::[email protected]@0000935015
SEC-HEADER||FILER||MAIL-ADDRESS$$STATE::[email protected]@0000935015
SEC-HEADER||FILER||MAIL-ADDRESS$$ZIP::[email protected]@0000935015
SEC-HEADER||FILER||FORMER-COMPANY$$FORMER-CONFORMED-NAME::ARTISAN FUNDS [email protected]@0000935015
SEC-HEADER||FILER||FORMER-COMPANY$$DATE-CHANGED::[email protected]@0000935015
SEC-HEADER||FILER||FORMER-COMPANY1$$FORMER-CONFORMED-NAME::ZIEGLER FUNDS [email protected]@0000935015
SEC-HEADER||FILER||FORMER-COMPANY1$$DATE-CHANGED::[email protected]@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$CONFORMED-NAME::ARTISAN PARTNERS FUNDS [email protected]@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$CIK::[email protected]@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$IRS-NUMBER::[email protected]@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$STATE-OF-INCORPORATION::[email protected]@0000935015
SEC-HEADER||FILER1||COMPANY-DATA1$$FISCAL-YEAR-END::[email protected]@0000935015
SEC-HEADER||FILER1||FILING-VALUES1$$FORM-TYPE::[email protected]@0000935015
SEC-HEADER||FILER1||FILING-VALUES1$$ACT::[email protected]@0000935015
SEC-HEADER||FILER1||FILING-VALUES1$$FILE-NUMBER::[email protected]@0000935015
SEC-HEADER||FILER1||FILING-VALUES1$$FILM-NUMBER::[email protected]@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$STREET1::875 EAST WISCONSIN AVE STE [email protected]@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$CITY::[email protected]@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$STATE::[email protected]@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$ZIP::[email protected]@0000935015
SEC-HEADER||FILER1||BUSINESS-ADDRESS1$$PHONE::[email protected]@0000935015
SEC-HEADER||FILER1||MAIL-ADDRESS1$$STREET1::875 EAST WISCONSIN AVE STE [email protected]@0000935015
SEC-HEADER||FILER1||MAIL-ADDRESS1$$CITY::[email protected]@0000935015
SEC-HEADER||FILER1||MAIL-ADDRESS1$$STATE::[email protected]@0000935015
SEC-HEADER||FILER1||MAIL-ADDRESS1$$ZIP::[email protected]@0000935015
SEC-HEADER||FILER1||FORMER-COMPANY2$$FORMER-CONFORMED-NAME::ARTISAN FUNDS [email protected]@0000935015
SEC-HEADER||FILER1||FORMER-COMPANY2$$DATE-CHANGED::[email protected]@0000935015
SEC-HEADER||FILER1||FORMER-COMPANY3$$FORMER-CONFORMED-NAME::ZIEGLER FUNDS [email protected]@0000935015
SEC-HEADER||FILER1||FORMER-COMPANY3$$DATE-CHANGED::[email protected]@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