Парсер SGML в Java? - PullRequest
       40

Парсер SGML в Java?

20 голосов
/ 02 февраля 2011

Я ищу синтаксический анализатор в 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.

Спасибо!:)

Ответы [ 6 ]

4 голосов
/ 07 марта 2011

У меня есть несколько подходов к этой проблеме

Первое, что вы сделали - проверьте, достаточно ли близок к XML документ sgml для работы стандартного синтаксического анализатора SAX.

Второй - сделать то же самое с HTML-парсерами. Хитрость здесь в том, чтобы найти тот, который не игнорирует не-HTML элементы.

Я нашел несколько синтаксических анализаторов Java SGML, в частности, при поиске "sgml parser Java". Я не знаю, насколько хорошо они работают.

Последний шаг - взять стандартный (не Java) синтаксический анализатор SGML и преобразовать документы в то, что вы можете прочитать на Java.

Похоже, вы смогли работать с первым шагом.

2 голосов
/ 18 февраля 2013

Я использую OpenSP через JNI, так как кажется, что нет чистого парсера Java SGML. Я написал экспериментальную SAX-подобную оболочку, которая доступна по адресу http://sourceforge.net/projects/sasgml (конечно, у нее есть все недостатки JNI ... но этого было достаточно для моих требований).

Другой подход заключается в преобразовании документа в XML с использованием sx из Откройте SP , а затем запустите традиционный SAX-анализатор.

1 голос
/ 05 сентября 2012

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.

1 голос
/ 15 февраля 2012

В настоящее время нет API для синтаксического анализа SGML с использованием Java. Также нет API или библиотеки для преобразования SGML в XML и последующего анализа с использованием Java. С учетом того, что SGML заменяет статус SGML для всех проектов, над которыми я работал до сих пор, я не думаю, что в этой области будет какая-либо работа, но это только предположение.

Здесь - это некоторый код с открытым исходным кодом из университета, который делает это, однако я не пробовал его, и вам придется искать, чтобы найти другие зависимые классы. Я считаю, что единственное жизнеспособное решение в Java потребовало бы регулярных выражений.

Кроме того, здесь есть ссылка для общедоступного программного обеспечения SGML / XML.

0 голосов
/ 20 сентября 2017

Хотя это очень старый пост, и я не утверждаю, что ответ, который я даю, идеален, но он послужил моей цели. Так что я держу этот код, который я написал, используя стек, чтобы получить данные способом, который требовался в моем случае. Я надеюсь, что это может быть полезно для других.

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
        }

    }

Выход:

Источник файла: 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 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
0 голосов
/ 04 июля 2012

Если ваш HTML, который вы анализируете, это может сделать:

http://ccil.org/~cowan/XML/tagsoup/

...