바둑 배우기 시도 - 유령이 휴고에게 3
소개
우리는 back once again에서
ghost2hugo
프로토타입에 대한 작업을 계속할 것입니다. 지금까지 JSON 파일을 열고 데이터를 메모리에 로드하고 첫 번째 게시물에 대한 Markdown을 인쇄할 수 있습니다. 다음 단계는 백업에 포함된 모든 게시물을 읽고 처리할 수 있는지 확인하는 것입니다.루핑
단일 기사를 인쇄하는 모든 코드를 각 기사를 인쇄하는 루프로 대체할 것입니다. 복습을 위해 첫 번째 기사를 인쇄하는 코드는 다음과 같습니다.
c := "`" + db.Db[0].Data.Posts[0].Mobiledoc + "`"
un, err := strconv.Unquote(c)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%v", un)
var md Mobiledoc
err = json.Unmarshal([]byte(un), &md)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%#v", md)
card := md.Cards[0][1]
fmt.Printf("\n\ncard: %#v\n", card)
bbb := card.(map[string]interface{})
fmt.Println(bbb["markdown"])
이것의 대부분은 우리의 새로운 루프 안에 있을 것입니다.
for i := 0; i < len(db.Db[0].Data.Posts); i++ {
fmt.Println(db.Db[0].Data.Posts[i].Title)
fmt.Println(db.Db[0].Data.Posts[i].Slug)
fmt.Println(db.Db[0].Data.Posts[i].Status)
fmt.Println(db.Db[0].Data.Posts[i].CreatedAt)
fmt.Println(db.Db[0].Data.Posts[i].UpdatedAt)
cc := "`" + db.Db[0].Data.Posts[i].Mobiledoc + "`"
ucn, err := strconv.Unquote(cc)
if err != nil {
fmt.Println(err, ucn)
}
fmt.Printf("\n\n\n%v\n\n\n", ucn)
var md Mobiledoc
err = json.Unmarshal([]byte(ucn), &md)
if err != nil {
fmt.Println(err)
}
card := md.Cards[0][1]
bbb := card.(map[string]interface{})
fmt.Println(bbb["markdown"])
}
}
그리고 이번에 코드를 실행하면 많은 기사가 날아가는 것을 볼 수 있습니다! 즉, 오류가 발생할 때까지!
invalid syntax
오류는 이것이 strconv.Unquote()
의 문제임을 나타냅니다.invalid syntax
unexpected end of JSON input
panic: runtime error: index out of range [0] with length 0
goroutine 1 [running]:
main.main()
/Users/steve/Code/ghost2hugo/main.go:214 +0x769
exit status 2
장애물
글쎄요, 우리 코드가 그렇게 충돌하게 만들 수는 없습니다! 문제를 자세히 살펴보고 문제를 해결할 수 있는지 살펴보겠습니다. 자, 이제 모든 디버깅 기술의 마스터입니다!
fmt.Println
를 추가하여 텍스트 덩어리를 출력합니다. fmt.Println(cc)
코드를 다시 실행하면 예상대로 충돌이 발생하지만 이번에는 문제 텍스트가 표시됩니다.
`{"version":"0.3.1","markups":[],"atoms":[],"cards":[["markdown",{"cardName":"card-markdown","markdown":"\n* Incresed title to 64 characters. Should be more then enough. \n * ics and other code work over at angstridden dot net tonight.\n\nALTER TABLE `posts` CHANGE `posttitle` `posttitle` VARCHAR( 64 ) NOT NULL\n\n\n"}]],"sections":[[10,0]],"ghostVersion":"3.0"}`
문제가 보이십니까? 예, 문자열 변환이 예상대로 작동하지 않는 원인이 되는 Markdown에 백틱이 있는 것 같습니다. 이 문제를 해결하기 위해 백틱을 다른 것으로 변경하기 위해 변환하기 전에 간단한 작업
strings.ReplaceAll
을 수행할 것입니다. 그런 다음 일반 텍스트를 얻기 위해 해당 프로세스를 되돌릴 수 있습니다. 백틱을 "%'
"로 교체합니다. c := strings.ReplaceAll(db.Db[0].Data.Posts[i].Mobiledoc, "`", "%'")
cc := "`" + c + "`"
"인용 해제"한 후 다른 항목
strings.ReplaceAll
을 실행하여 다시 변환할 수 있습니다. ucn = strings.ReplaceAll(ucn, "%'", "`")
다시 실행하면 또 다른 문제가 발생합니다!
---
Archives
archives-post
published
2007-07-01 09:46:18 +0000 UTC
2007-08-12 20:50:02 +0000 UTC
`{"version":"0.3.1","markups":[],"atoms":[],"cards":[],"sections":[[1,"p",[[0,[],0,""]]]],"ghostVersion":"3.0"}`
panic: runtime error: index out of range [0] with length 0
goroutine 1 [running]:
main.main()
/Users/steve/Code/ghost2hugo/main.go:214 +0x7a6
exit status 2
아!
더 많은 장애물
이전 게시물의 순진한 구현이 우리를 물기 위해 돌아왔습니다! 우리는 카드가 존재한다고 가정했습니다.
card := md.Cards[0][1]
bbb := card.(map[string]interface{})
반환된 JSON을 보면 이를 확인할 수 있습니다.
{"version":"0.3.1","markups":[],"atoms":[],"cards":[],"sections":[[1,"p",[[0,[],0,""]]]],"ghostVersion":"3.0"}
이제 카드 필드가 비어 있는지 어떻게 확인합니까?! 나는 그것에 약간의 국수를 넣고
reflect.ValueOf().Len()
를 사용하는 것이 가장 좋은 방법이라고 생각했습니다. 그러면 md.Cards
의 길이를 확인하여 실제로 일부 데이터가 있는지 확인합니다. if reflect.ValueOf(md.Cards).Len() > 0 {
card := md.Cards[0][1]
bbb := card.(map[string]interface{})
fmt.Println(bbb["markdown"])
}
다시 실행하면 모든 게시물처럼 보이는 것을 얻습니다. 이상하게 보이는 최종 초안을 제외하고! 이것은 Markdown 카드가 없는 것으로 밝혀졌습니다. 이것뿐인가요? Markdown으로 변환하는 것이 고통스러울 수 있기 때문에 확실히 그렇게 되기를 바랍니다.
Questing
questing
draft
2019-08-23 21:26:44 +0000 UTC
2021-04-12 04:53:26 +0000 UTC
`{"version":"0.3.1","atoms":[],"cards":[["paywall",{}]],"markups":[["a",["href","https://shindakun.dev"]],["a",["href","https://dev.to/shindakun"]]],"sections":[[1,"p",[[0,[],0,"It's been quite sometime since I've posted anything here. I've done a bit of posting over on "],[0,[0],1,"shindakun.dev"],[0,[],0," and over on "],[0,[1],1,"DEV"],[0,[],0," which has been kind of nice. But, those don't really cover gaming at all. But, I updated the site recently and everyone once in a while I use the site to try something out for work and seeing an old post over and over was no good."]]],[1,"p",[[0,[],0,"I only seem to have a small sliver of time for gaming now. With everything else I want/need to get done there is only so much time. Heed this warning - don't get older! Just kidding, it's not so bad."]]],[1,"p",[[0,[],0,"My 5 year old hasn't been introduced into gaming much outside of some basic games she can play on her tablet. I have discovered that she enjoys watching me play the digital version of Warhammer Quest. Which is good since she's going to be getting a crash course in some more difficult board games sooner or later. I have a copy of the Gloomhaven digital board game and the boxed game (and expansion) but haven't actually event opened it yet. Maybe I should fix that this weekend..."]]],[10,0],[1,"p",[]]],"ghostVersion":"3.0"}`
json: cannot unmarshal string into Go struct field Mobiledoc.sections of type int
<nil>
마지막 줄에 언마샬링 문제도 있는 것 같습니다. 지금은 쉽게 고칠 수 있습니다.
sections
가 아닌 Mobiledoc
를 사용하려면 struct
[][]interface{}
에서 [][]int
를 업데이트하면 됩니다.type Mobiledoc struct {
Version string `json:"version"`
Markups []interface{} `json:"markups"`
Atoms []interface{} `json:"atoms"`
Cards [][]interface{} `json:"cards"`
Sections [][]interface{} `json:"sections"`
GhostVersion string `json:"ghostVersion"`
}
다음번
우리는 지난 몇 개의 게시물에서 좋은 진전을 이루었습니다. 처음에는 필요한 것을 추출하는 것 같습니다. 약간의 리팩토링을 수행하고 현재 디버그 인쇄 문을 제거하고 변환기의 다음 부분을 준비할 준비가 된 것 같습니다.
이 게시물을 즐기십니까?
How about buying me a coffee?
신다쿤 / atlg
Dev.to에 올린 "Attempting to Learn Go" 게시물의 소스 저장소
Go 배우기 시도
여기에서 내가 작성하고 게시한 Go 학습 시도 게시물에 대해 작성한 코드를 찾을 수 있습니다.
포스트 색인
게시하다
암호
-
-
-
-
-
src
src
src
src
src
src
src
src
src
src
src
src
src
src
src
위 코드 참조
…
View on GitHub
코드 목록
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings"
"time"
)
type GhostDatabase struct {
Db []struct {
Meta struct {
ExportedOn int64 `json:"exported_on"`
Version string `json:"version"`
} `json:"meta"`
Data struct {
Posts []struct {
ID string `json:"id"`
UUID string `json:"uuid"`
Title string `json:"title"`
Slug string `json:"slug"`
Mobiledoc string `json:"mobiledoc"`
HTML string `json:"html"`
CommentID string `json:"comment_id"`
Plaintext string `json:"plaintext"`
FeatureImage interface{} `json:"feature_image"`
Featured int `json:"featured"`
Type string `json:"type"`
Status string `json:"status"`
Locale interface{} `json:"locale"`
Visibility string `json:"visibility"`
EmailRecipientFilter string `json:"email_recipient_filter"`
AuthorID string `json:"author_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
PublishedAt time.Time `json:"published_at"`
CustomExcerpt interface{} `json:"custom_excerpt"`
CodeinjectionHead interface{} `json:"codeinjection_head"`
CodeinjectionFoot interface{} `json:"codeinjection_foot"`
CustomTemplate interface{} `json:"custom_template"`
CanonicalURL interface{} `json:"canonical_url"`
} `json:"posts"`
PostsAuthors []struct {
ID string `json:"id"`
PostID string `json:"post_id"`
AuthorID string `json:"author_id"`
SortOrder int `json:"sort_order"`
} `json:"posts_authors"`
PostsMeta []interface{} `json:"posts_meta"`
PostsTags []struct {
ID string `json:"id"`
PostID string `json:"post_id"`
TagID string `json:"tag_id"`
SortOrder int `json:"sort_order"`
} `json:"posts_tags"`
Roles []struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"roles"`
RolesUsers []struct {
ID string `json:"id"`
RoleID string `json:"role_id"`
UserID string `json:"user_id"`
} `json:"roles_users"`
Settings []struct {
ID string `json:"id"`
Group string `json:"group"`
Key string `json:"key"`
Value string `json:"value"`
Type string `json:"type"`
Flags interface{} `json:"flags"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"settings"`
Tags []struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description interface{} `json:"description"`
FeatureImage interface{} `json:"feature_image"`
ParentID interface{} `json:"parent_id"`
Visibility string `json:"visibility"`
OgImage interface{} `json:"og_image"`
OgTitle interface{} `json:"og_title"`
OgDescription interface{} `json:"og_description"`
TwitterImage interface{} `json:"twitter_image"`
TwitterTitle interface{} `json:"twitter_title"`
TwitterDescription interface{} `json:"twitter_description"`
MetaTitle interface{} `json:"meta_title"`
MetaDescription interface{} `json:"meta_description"`
CodeinjectionHead interface{} `json:"codeinjection_head"`
CodeinjectionFoot interface{} `json:"codeinjection_foot"`
CanonicalURL interface{} `json:"canonical_url"`
AccentColor interface{} `json:"accent_color"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"tags"`
Users []struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Password string `json:"password"`
Email string `json:"email"`
ProfileImage string `json:"profile_image"`
CoverImage interface{} `json:"cover_image"`
Bio interface{} `json:"bio"`
Website interface{} `json:"website"`
Location interface{} `json:"location"`
Facebook interface{} `json:"facebook"`
Twitter interface{} `json:"twitter"`
Accessibility string `json:"accessibility"`
Status string `json:"status"`
Locale interface{} `json:"locale"`
Visibility string `json:"visibility"`
MetaTitle interface{} `json:"meta_title"`
MetaDescription interface{} `json:"meta_description"`
Tour interface{} `json:"tour"`
LastSeen time.Time `json:"last_seen"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"users"`
} `json:"data"`
} `json:"db"`
}
type Mobiledoc struct {
Version string `json:"version"`
Markups []interface{} `json:"markups"`
Atoms []interface{} `json:"atoms"`
Cards [][]interface{} `json:"cards"`
Sections [][]interface{} `json:"sections"`
GhostVersion string `json:"ghostVersion"`
}
func main() {
fmt.Println("ghost2hugo")
file, err := os.Open("shindakun-dot-net.ghost.2022-03-18-22-02-58.json")
if err != nil {
fmt.Println(err)
}
defer file.Close()
b, err := io.ReadAll(file)
if err != nil {
fmt.Println(err)
}
var db GhostDatabase
err = json.Unmarshal(b, &db)
if err != nil {
fmt.Println(err)
}
for i := 0; i < len(db.Db[0].Data.Posts); i++ {
fmt.Println(db.Db[0].Data.Posts[i].Title)
fmt.Println(db.Db[0].Data.Posts[i].Slug)
fmt.Println(db.Db[0].Data.Posts[i].Status)
fmt.Println(db.Db[0].Data.Posts[i].CreatedAt)
fmt.Println(db.Db[0].Data.Posts[i].UpdatedAt)
c := strings.ReplaceAll(db.Db[0].Data.Posts[i].Mobiledoc, "`", "%'")
cc := "`" + c + "`"
fmt.Println(cc)
ucn, err := strconv.Unquote(cc)
if err != nil {
fmt.Println(err, ucn)
}
ucn = strings.ReplaceAll(ucn, "%'", "`")
var md Mobiledoc
err = json.Unmarshal([]byte(ucn), &md)
if err != nil {
fmt.Println(err)
}
if reflect.ValueOf(md.Cards).Len() > 0 {
card := md.Cards[0][1]
bbb := card.(map[string]interface{})
fmt.Println(bbb["markdown"])
}
fmt.Println("---")
}
}
Reference
이 문제에 관하여(바둑 배우기 시도 - 유령이 휴고에게 3), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/shindakun/attempting-to-learn-go-ghost-to-hugo-3-31p4
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings"
"time"
)
type GhostDatabase struct {
Db []struct {
Meta struct {
ExportedOn int64 `json:"exported_on"`
Version string `json:"version"`
} `json:"meta"`
Data struct {
Posts []struct {
ID string `json:"id"`
UUID string `json:"uuid"`
Title string `json:"title"`
Slug string `json:"slug"`
Mobiledoc string `json:"mobiledoc"`
HTML string `json:"html"`
CommentID string `json:"comment_id"`
Plaintext string `json:"plaintext"`
FeatureImage interface{} `json:"feature_image"`
Featured int `json:"featured"`
Type string `json:"type"`
Status string `json:"status"`
Locale interface{} `json:"locale"`
Visibility string `json:"visibility"`
EmailRecipientFilter string `json:"email_recipient_filter"`
AuthorID string `json:"author_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
PublishedAt time.Time `json:"published_at"`
CustomExcerpt interface{} `json:"custom_excerpt"`
CodeinjectionHead interface{} `json:"codeinjection_head"`
CodeinjectionFoot interface{} `json:"codeinjection_foot"`
CustomTemplate interface{} `json:"custom_template"`
CanonicalURL interface{} `json:"canonical_url"`
} `json:"posts"`
PostsAuthors []struct {
ID string `json:"id"`
PostID string `json:"post_id"`
AuthorID string `json:"author_id"`
SortOrder int `json:"sort_order"`
} `json:"posts_authors"`
PostsMeta []interface{} `json:"posts_meta"`
PostsTags []struct {
ID string `json:"id"`
PostID string `json:"post_id"`
TagID string `json:"tag_id"`
SortOrder int `json:"sort_order"`
} `json:"posts_tags"`
Roles []struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"roles"`
RolesUsers []struct {
ID string `json:"id"`
RoleID string `json:"role_id"`
UserID string `json:"user_id"`
} `json:"roles_users"`
Settings []struct {
ID string `json:"id"`
Group string `json:"group"`
Key string `json:"key"`
Value string `json:"value"`
Type string `json:"type"`
Flags interface{} `json:"flags"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"settings"`
Tags []struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description interface{} `json:"description"`
FeatureImage interface{} `json:"feature_image"`
ParentID interface{} `json:"parent_id"`
Visibility string `json:"visibility"`
OgImage interface{} `json:"og_image"`
OgTitle interface{} `json:"og_title"`
OgDescription interface{} `json:"og_description"`
TwitterImage interface{} `json:"twitter_image"`
TwitterTitle interface{} `json:"twitter_title"`
TwitterDescription interface{} `json:"twitter_description"`
MetaTitle interface{} `json:"meta_title"`
MetaDescription interface{} `json:"meta_description"`
CodeinjectionHead interface{} `json:"codeinjection_head"`
CodeinjectionFoot interface{} `json:"codeinjection_foot"`
CanonicalURL interface{} `json:"canonical_url"`
AccentColor interface{} `json:"accent_color"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"tags"`
Users []struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Password string `json:"password"`
Email string `json:"email"`
ProfileImage string `json:"profile_image"`
CoverImage interface{} `json:"cover_image"`
Bio interface{} `json:"bio"`
Website interface{} `json:"website"`
Location interface{} `json:"location"`
Facebook interface{} `json:"facebook"`
Twitter interface{} `json:"twitter"`
Accessibility string `json:"accessibility"`
Status string `json:"status"`
Locale interface{} `json:"locale"`
Visibility string `json:"visibility"`
MetaTitle interface{} `json:"meta_title"`
MetaDescription interface{} `json:"meta_description"`
Tour interface{} `json:"tour"`
LastSeen time.Time `json:"last_seen"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"users"`
} `json:"data"`
} `json:"db"`
}
type Mobiledoc struct {
Version string `json:"version"`
Markups []interface{} `json:"markups"`
Atoms []interface{} `json:"atoms"`
Cards [][]interface{} `json:"cards"`
Sections [][]interface{} `json:"sections"`
GhostVersion string `json:"ghostVersion"`
}
func main() {
fmt.Println("ghost2hugo")
file, err := os.Open("shindakun-dot-net.ghost.2022-03-18-22-02-58.json")
if err != nil {
fmt.Println(err)
}
defer file.Close()
b, err := io.ReadAll(file)
if err != nil {
fmt.Println(err)
}
var db GhostDatabase
err = json.Unmarshal(b, &db)
if err != nil {
fmt.Println(err)
}
for i := 0; i < len(db.Db[0].Data.Posts); i++ {
fmt.Println(db.Db[0].Data.Posts[i].Title)
fmt.Println(db.Db[0].Data.Posts[i].Slug)
fmt.Println(db.Db[0].Data.Posts[i].Status)
fmt.Println(db.Db[0].Data.Posts[i].CreatedAt)
fmt.Println(db.Db[0].Data.Posts[i].UpdatedAt)
c := strings.ReplaceAll(db.Db[0].Data.Posts[i].Mobiledoc, "`", "%'")
cc := "`" + c + "`"
fmt.Println(cc)
ucn, err := strconv.Unquote(cc)
if err != nil {
fmt.Println(err, ucn)
}
ucn = strings.ReplaceAll(ucn, "%'", "`")
var md Mobiledoc
err = json.Unmarshal([]byte(ucn), &md)
if err != nil {
fmt.Println(err)
}
if reflect.ValueOf(md.Cards).Len() > 0 {
card := md.Cards[0][1]
bbb := card.(map[string]interface{})
fmt.Println(bbb["markdown"])
}
fmt.Println("---")
}
}
Reference
이 문제에 관하여(바둑 배우기 시도 - 유령이 휴고에게 3), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/shindakun/attempting-to-learn-go-ghost-to-hugo-3-31p4텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)