Разобрать файл Markdown для объекта JSON в Java - PullRequest
0 голосов
/ 03 марта 2019

Что лучше всего подходит для анализа файла Markdown в Java и преобразования его в объект JSON?Ранее я использовал свою пользовательскую реализацию, но она довольно сильно зависела от конкретной структуры файла Markdown, и мне часто приходилось менять ее из-за обновлений структуры файла.Я хотел бы использовать что-то более общее и абстрактное - какие варианты я могу выбрать?

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

Вы можете использовать commonmark-java для анализа и генерации object представления и Jackson для сериализации от object до JSON.Вы можете попробовать реализовать rg.commonmark.renderer.Renderer или расширить тот, который уже существует.Например, я использовал org.commonmark.renderer.html.HtmlRenderer в качестве примера, чтобы написать что-то похожее:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.commonmark.Extension;
import org.commonmark.internal.renderer.NodeRendererMap;
import org.commonmark.internal.util.Escaping;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.NodeRenderer;
import org.commonmark.renderer.Renderer;
import org.commonmark.renderer.html.AttributeProvider;
import org.commonmark.renderer.html.AttributeProviderContext;
import org.commonmark.renderer.html.AttributeProviderFactory;
import org.commonmark.renderer.html.CoreHtmlNodeRenderer;
import org.commonmark.renderer.html.HtmlNodeRendererContext;
import org.commonmark.renderer.html.HtmlNodeRendererFactory;
import org.commonmark.renderer.html.HtmlWriter;

import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class CommonMarkApp {

    public static void main(String[] args) throws Exception {
        File mdFile = new File("./resource/markdown.md").getAbsoluteFile();

        Parser parser = Parser.builder().build();
        Node document = parser.parseReader(new FileReader(mdFile));
        ObjectRenderer renderer = ObjectRenderer.builder().build();
        renderer.render(document);
        List<Object> nodes = renderer.getNodes();

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        System.out.println(mapper.writeValueAsString(nodes));
    }
}

class ObjectRenderer implements Renderer {

    private final String softbreak;
    private final boolean escapeHtml;
    private final boolean percentEncodeUrls;
    private final List<AttributeProviderFactory> attributeProviderFactories;
    private final List<HtmlNodeRendererFactory> nodeRendererFactories;
    private final ObjectWriter objectWriter = new ObjectWriter();

    private ObjectRenderer(Builder builder) {
        this.softbreak = builder.softbreak;
        this.escapeHtml = builder.escapeHtml;
        this.percentEncodeUrls = builder.percentEncodeUrls;
        this.attributeProviderFactories = new ArrayList<>(builder.attributeProviderFactories);

        this.nodeRendererFactories = new ArrayList<>(builder.nodeRendererFactories.size() + 1);
        this.nodeRendererFactories.addAll(builder.nodeRendererFactories);
        // Add as last. This means clients can override the rendering of core nodes if they want.
        this.nodeRendererFactories.add(new HtmlNodeRendererFactory() {
            @Override
            public NodeRenderer create(HtmlNodeRendererContext context) {
                return new CoreHtmlNodeRenderer(context);
            }
        });
    }

    public static Builder builder() {
        return new Builder();
    }

    @Override
    public void render(Node node, Appendable output) {
        RendererContext context = new RendererContext(objectWriter);
        context.render(node);
    }

    @Override
    public String render(Node node) {
        render(node, null);
        return "Invoke getNodes()!";
    }

    public List<Object> getNodes() {
        return objectWriter.getNodes();
    }

    public static class Builder {

        private String softbreak = "\n";
        private boolean escapeHtml = true;
        private boolean percentEncodeUrls = true;
        private List<AttributeProviderFactory> attributeProviderFactories = new ArrayList<>();
        private List<HtmlNodeRendererFactory> nodeRendererFactories = new ArrayList<>();

        public ObjectRenderer build() {
            return new ObjectRenderer(this);
        }

        public Builder attributeProviderFactory(AttributeProviderFactory attributeProviderFactory) {
            this.attributeProviderFactories.add(attributeProviderFactory);
            return this;
        }

        public Builder nodeRendererFactory(HtmlNodeRendererFactory nodeRendererFactory) {
            this.nodeRendererFactories.add(nodeRendererFactory);
            return this;
        }

        public Builder extensions(Iterable<? extends Extension> extensions) {
            for (Extension extension : extensions) {
                if (extension instanceof ObjectRendererExtension) {
                    ObjectRendererExtension htmlRendererExtension = (ObjectRendererExtension) extension;
                    htmlRendererExtension.extend(this);
                }
            }
            return this;
        }
    }

    public interface ObjectRendererExtension extends Extension {
        void extend(Builder rendererBuilder);
    }

    private class RendererContext implements HtmlNodeRendererContext, AttributeProviderContext {

        private final HtmlWriter htmlWriter;
        private final List<AttributeProvider> attributeProviders;
        private final NodeRendererMap nodeRendererMap = new NodeRendererMap();

        private RendererContext(HtmlWriter htmlWriter) {
            this.htmlWriter = htmlWriter;

            attributeProviders = new ArrayList<>(attributeProviderFactories.size());
            for (AttributeProviderFactory attributeProviderFactory : attributeProviderFactories) {
                attributeProviders.add(attributeProviderFactory.create(this));
            }

            // The first node renderer for a node type "wins".
            for (int i = nodeRendererFactories.size() - 1; i >= 0; i--) {
                HtmlNodeRendererFactory nodeRendererFactory = nodeRendererFactories.get(i);
                NodeRenderer nodeRenderer = nodeRendererFactory.create(this);
                nodeRendererMap.add(nodeRenderer);
            }
        }

        @Override
        public boolean shouldEscapeHtml() {
            return escapeHtml;
        }

        @Override
        public String encodeUrl(String url) {
            if (percentEncodeUrls) {
                return Escaping.percentEncodeUrl(url);
            } else {
                return url;
            }
        }

        @Override
        public Map<String, String> extendAttributes(Node node, String tagName, Map<String, String> attributes) {
            Map<String, String> attrs = new LinkedHashMap<>(attributes);
            setCustomAttributes(node, tagName, attrs);
            return attrs;
        }

        @Override
        public HtmlWriter getWriter() {
            return htmlWriter;
        }

        @Override
        public String getSoftbreak() {
            return softbreak;
        }

        @Override
        public void render(Node node) {
            nodeRendererMap.render(node);
        }

        private void setCustomAttributes(Node node, String tagName, Map<String, String> attrs) {
            for (AttributeProvider attributeProvider : attributeProviders) {
                attributeProvider.setAttributes(node, tagName, attrs);
            }
        }
    }
}

class ObjectWriter extends HtmlWriter {

    private List<Object> nodes = new ArrayList<>();

    public ObjectWriter() {
        super(null);
    }

    @Override
    public void raw(String s) {
        nodes.add(Collections.singletonMap("raw", s));
    }

    @Override
    public void text(String text) {
        nodes.add(Collections.singletonMap("text", text));
    }

    @Override
    public void tag(String name) {
    }

    @Override
    public void tag(String name, Map<String, String> attrs) {
        nodes.add(Collections.singletonMap(name, attrs));
    }

    @Override
    public void tag(String name, Map<String, String> attrs, boolean voidElement) {
        tag(name, attrs);
    }

    @Override
    public void line() {
    }

    @Override
    protected void append(String s) {
        nodes.add(Collections.singletonMap("line", s));
    }

    public List<Object> getNodes() {
        return nodes;
    }
}

Для файла ниже markdown.md:

List
- __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image
  resize in browser.
- __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly
  i18n with plurals support and easy syntax.

## Emphasis
**This is bold text**
__This is bold text__

Start numbering with offset:
57. foo
1. bar

Над отпечатками приложения:

[ {
  "p" : { }
}, {
  "text" : "List"
}, {
  "ul" : { }
}, {
  "li" : { }
}, {
  "strong" : { }
}, {
  "a" : {
    "href" : "https://nodeca.github.io/pica/demo/"
  }
}, {
  "text" : "pica"
}, {
  "text" : " - high quality and fast image"
}, {
  "raw" : "\n"
}, {
  "text" : "resize in browser."
}, {
  "li" : { }
}, {
  "strong" : { }
}, {
  "a" : {
    "href" : "https://github.com/nodeca/babelfish/"
  }
}, {
  "text" : "babelfish"
}, {
  "text" : " - developer friendly"
}, {
  "raw" : "\n"
}, {
  "text" : "i18n with plurals support and easy syntax."
}, {
  "h2" : { }
}, {
  "text" : "Emphasis"
}, {
  "p" : { }
}, {
  "strong" : { }
}, {
  "text" : "This is bold text"
}, {
  "raw" : "\n"
}, {
  "strong" : { }
}, {
  "text" : "This is bold text"
}, {
  "p" : { }
}, {
  "text" : "Start numbering with offset:"
}, {
  "raw" : "\n"
}, {
  "text" : "57. foo"
}, {
  "ol" : { }
}, {
  "li" : { }
}, {
  "text" : "bar"
} ]
0 голосов
/ 03 марта 2019

Я не использовал их, но похоже, что commonmark-java или flexmark-java могут обрабатывать синтаксический анализ.

Они оба поддерживают подключаемый модульрендеры, чтобы вы могли написать JSON.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...