Vintage appMaker의 Tech Blog

[Flutter] dart로 opml 파싱 본문

Source code or Tip/Flutter & Dart

[Flutter] dart로 opml 파싱

VintageappMaker 2023. 10. 31. 17:37

 


 

dart를 이용한 간단한 opml 제어

opml(Outline Processor Markup Language)은 구조적 글씨기에 사용되는 XML의 확장문법이다.
dart에서는 opml을 파싱, 생성할 수 있는 opml 패키지를 제공한다.

다음 예제는 다음과 같다.

  • opml 문서를 파싱하는 하여 HTML로 만드는 예제
  • opml을 코드로 만드는 예제
  1. 생성
dart create opmltest
  1. 설치
dart pub add opml 
dart pub add markdown
  1. 예제 - opmltest.dart
import 'dart:io';
import 'package:markdown/markdown.dart';
import 'package:opml/opml.dart';

// 간단한 Outlline용 tag 만들기
class OutlineHTML {
  int indent = 1;

  StringBuffer sBuff = StringBuffer();

  // text를 추가
  void addText(String s) {
    String htmlStr = extractMarkDownToHtml(s);
    sBuff.writeln('${makeOutline(indent)} $htmlStr <br>');
  }

  // 필요한 HTML만 추출한다.
  String extractMarkDownToHtml(String s) {
    String htmlStr = markdownToHtml(s);

    htmlStr = htmlStr.replaceAll("<p>", "");
    htmlStr = htmlStr.replaceAll("</p>", "");
    htmlStr = htmlStr.replaceAll("<ol>", "");
    htmlStr = htmlStr.replaceAll("</ol>", "");
    htmlStr = htmlStr.replaceAll("<li>", "");
    htmlStr = htmlStr.replaceAll("</li>", "");
    htmlStr = htmlStr.replaceAll("</li>", "");
    htmlStr = htmlStr.replaceAll(RegExp(r'<ol\s[^>]*>'), '');
    return htmlStr;
  }

  // title 추가
  void addTitle(String s) {
    sBuff.writeln('<h1>$s</h1>');
  }

  // 첫번째 depth의 제목
  void addCategory(String s) {
    sBuff.writeln('<h4>$s</h4>');
  }

  // 아웃라인 만들기
  String makeOutline(int indx) {
    String s = "&nbsp  &nbsp" * indent;
    return (indent == 0) ? s : "$s-";
  }

  @override
  String toString() {
    return sBuff.toString();
  }
}

void main() {
  print('======> Read Example_in.xml to HTML');
  readExample();

  print('======> Write example_out.xml(make OPML with code)');
  writeSimpleOPML();
}

OutlineHTML html = OutlineHTML();

// 재귀적으로 child를 찾아서 출력
void readChildren(OpmlOutline category) {
  html.addText(category.text!);
  for (var feed in category.children!) {
    html.indent++;
    readChildren(feed);
    html.indent--;
  }
}

// OPML에서 값을 읽어온다.
void readExample() {
  final xml = File('./example_in.xml').readAsStringSync();
  final doc = OpmlDocument.parse(xml);
  html.addTitle('${doc.head.title}');
  for (var category in doc.body) {
    html.addCategory('▪ ${category.text}');

    for (var feed in category.children!) {
      readChildren(feed);
    }
  }

  writeHTML(html.toString());
}

// Write Simple 예제
void writeSimpleOPML() {
  final head = OpmlHeadBuilder().title('Example Export').build();
  final body = <OpmlOutline>[];

  body.add(OpmlOutlineBuilder()
      .text('입력되는 내용')
      .title('타이틀')
      .addChild(OpmlOutlineBuilder()
          .type('text')
          .text('1.보여지는 텍스트')
          .title('Title일 뿐')
          .addChild(OpmlOutlineBuilder().text("👋 자식항목").title('').build())
          .build())
      .addChild(OpmlOutlineBuilder()
          .type('text')
          .text('2. 두번째 텍스트')
          .title('Title일 뿐')
          .build())
      .build());

  [for (int i = 0; i < 10; i++) i].forEach((element) {
    body.add(OpmlOutlineBuilder()
        .text('$element 입력입니다.')
        .title('$element')
        .addChild(OpmlOutlineBuilder().text("👋").title('👋').build())
        .build());
  });

  final opml = OpmlDocument(
    head: head,
    body: body,
  );

  final xml = opml.toXmlString(pretty: true);
  File file = File('example_out.xml');
  file.writeAsString(xml);
  print(xml);
}

// write HTML
void writeHTML(String s) {
  String htmlTemplate = """

<!DOCTYPE html>
<html lang="ko"> 
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
__replace__here__
</body>
</html>
  """;

  String html = htmlTemplate.replaceAll("__replace__here__", s);
  final file = File("example.html");
  file.writeAsString(html);
}

위의 예제에서는 child의 정보를 가져오기 위해 readChildren() 함수를 재귀적으로 구현했다. 그리고 text에서 MarkDown 문법을 사용했을 경우, 파싱을 하기 위해 markdownToHtml()을 사용했다. 사용한 example_in.xml은 다음과 같다. 

 

4. opml 파일( example_in.xml )

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<opml version="2.0">

    <head>

        <title>Outline 문서작성을 시작하자</title>
        <flavor>dynalist</flavor>
        <source>https://dynalist.io</source>
        <ownerName>vintage appMaker</ownerName>
        <ownerEmail>adsloader99@gmail.com</ownerEmail>

    </head>

    <body>

        <outline text="아웃라인 문서란 ">
            <outline text="정보를 계층적 구조로 표현하고 정리하는 방법 "/>
            <outline text="아이디어, 개념, 계획, 프로젝트 조직화하고 전달하기 위해 사용"/>
            <outline text="아웃라인 문서 작성의  특징">
                <outline text="계층적 구조: 아웃라인 문서는 항목을 부모 및 자식 항목으로 구분하여 계층적으로 구조화를 통해 가독성 높임"/>
                <outline text="목차 및 서브-목차: 주제와 하위 주제 간의 관계를 명확하게 나타내기 위해 목차와 서브-목차를 사용"/>

                <outline text="순차적 맥락: 아웃라인 문서는 항목을 순서대로 나열하고 각 항목을 들여쓰기 등으로 쉽게 전달가능"/>
                <outline text="요약: 아웃라인은 많은 텍스트가 있는 내용이라도 구조화된 순서와 맥락을 통해 요약을 하는 효고"/>

            </outline>

            <outline text="아웃라인 문서의 활용">
                <outline text="학습:  정보를 시각화 정리"/>
                <outline text="발표 및 강의: Timeline을 기준으로 정보전달 계획 수립에 유리"/>
                <outline text="보고서 작성:  핵심내용과 전체흐름을 효과적으로 전달"/>
                <outline text="계획: 목표를 향한 Timeline 구성과 맥락(Context)를 구조화"/>
                <outline text="<img src='https://img1.daumcdn.net/thumb/C500x500/?fname=http://t1.daumcdn.net/brunch/service/user/4WjL/image/tBiU_abX7taddaBleHfTe-mfkr8.png' />"/>

            </outline>

        </outline>
        <outline text="OPML은 무엇인가?">
            <outline text="[OPML의 정의](https://ko.wikipedia.org/wiki/OPML) ">

                <outline text="Outline Process Markup langugae"/>
                <outline text="아웃라인 형태로 작성된 문서를 표준화한 XML 문서"/>

            </outline>

            <outline text="OPML(Outline Processor Markup Language) 지원 프로그램">

                <outline text="RSS 리더 및 뉴스 어그리게이터:">
                    <outline text="Feedly"/>

                    <outline text="Inoreader"/>

                    <outline text="The Old Reader"/>
                    <outline text="NewsBlur"/>
                    <outline text="Reeder (macOS 및 iOS용)"/>

                </outline>

                <outline text="아웃라인 편집기:">
                    <outline text="Fargo (웹 기반)"/>

                    <outline text="OmniOutliner (macOS 및 iOS용)"/>
                    <outline text="WorkFlowy (웹 기반)"/>
                    <outline text="dynalist(웹 기반)"/>

                </outline>

                <outline text="마인드맵:">
                    <outline text="대부분의 마인드맵 프로그램들"/>
                </outline>
            </outline>
        </outline>
        <outline text="아웃라인 문서의 활용법 ">
            <outline text="1. 데이터와 프로세스로 설계:">

                <outline text="**글쓰기도 프로그래밍과 크게 다르지 않다.** "/>

                <outline text="짧고 간결한 프로그래밍 예제를 만드는 것과 유사하다. "/>
                <outline text="`전달할 메시지:  데이터(변수와 값)`"/>
                <outline text="`글의 흐름(맥락): 함수와 로직`"/>
            </outline>
            <outline text="2. 설계 후, 코딩">

                <outline text="데이터와 맥락을 구조화한 이후"/>

                <outline text="항목 별 내용작성">
                    <outline text="단어정의(변수) ">

                        <outline text="주제어"/>
                        <outline text="필수단어 "/>

                    </outline>

                    <outline text="흐름구성(변수의 가공)">
                        <outline text="짧고 쉬운 흐름"/>
                        <outline text="조건문이 아닌 열거문"/>
                        <outline text="설명은 극단적으로 최소화"/>

                    </outline>

                    <outline text="결과(목적한 메시지전달)">
                        <outline text="목적한 주제어로 결과 얻기"/>
                        <outline text="논리적인가? 설득력이 있는가?"/>
                    </outline>
                </outline>

                <outline text="내용검수">
                    <outline text="사용된 단어의 가독성은?(일반용어로 변환가능한가?)"/>

                    <outline text="불필요한 변수는?(단어의 갯수를 줄이기)"/>
                    <outline text="불필요한 흐름은?(흐름을 1개로 단순통일하기)"/>

                </outline>

            </outline>
        </outline>
    </body>

</opml>
Comments