2021年7月7日水曜日

XMLはDOMで扱ったほうがいいわ

XMLからJSONへの変換をしようとしていて、encoding/xml使ったり、XSLで変換かけようかと思ったけど、XSLTは難解で、考え方は分ってきたけど、組みづらい・・・

やはりXMLはDOMで扱わないとダメよ

encoding/xmlとか使っても結局DOM作ろうとしちゃうし、DOM作らないと、XMLの表記方法への対応は出来ない。

たとえば、以下のようにnameが連続していないとき、name項目が一つしかないとき、nameの下に子ノードがあるときなど、汎用的なXMLでは、SAXやxsl的な方法での変換なんて出来ない。

<root>

 <list>

  <name>aiueo

    <special>あいうえお</special>

  </name>

  <name>kakikukeko</name>

  <URL>http://www.blablabla.com</URL>

  <name>sasisuseso</name>

 </list>

</root>

SAXやXSLは、きまった形のXMLでない対応できない。

この考え方が、xslを使えない奴にしてしまっている。

ていうか、xslで出来ることがHTML変換くらいなものなのだが、

JavaScript系のエンジニアは、JSONでそのまま扱いたいからxslなんて勉強しない。

そして余計にXMLが嫌われていく

xslもオブジェクト指向に毒されてしまっているのだと思う。


golangやってると、オブジェクト指向なんてどうでもよくなる。

(まったくオブジェクト指向なんて悪い夢を見ていたようだよ)

話を戻して、JSONへの変換元となるXMLは、形が無限の種類のXMLなので、SAXやXSLでは絶対に無理だ。

例えば上記の場合、name以下は全部強制的に配列にしたい。

nameの途中にURLタグが出てきちゃうので、nameで要素をまとめてJSON配列にしないといけない。

これは、encoding/xmlのtokenじゃ無理

一度読み込んでまとめ、ソートするなど工夫が必要だ。

つまりそれってDOMだよ


強制配列を実現するために全体をDATAタグで括って、プロパティでForceArrayを指定して変換できるように考えていた。

まず、このアトリビュートの取得をして、複数のXPATHをXSLのVariableに配列としてSplitしようかと思ったのだけど、xsl2.0じゃないとtokenize使えないし、xsl2.0なんて誰も実装してないし、SAXXONくらいだし、俺Java嫌いだし絶対に使わねー

go-xmldomでxml2json作ろうかと思ってまずはxmldomのテストプログラムを動かしてみた。

名前はxml2json.goだけど、機能はxml2jsonじゃありません。

単にテストプログラムをそのまま動かしただけです

Qiitaみたいですみません

===xml2json.go===

package xml2json

import (
    "fmt"

    xmldom "github.com/subchen/go-xmldom"
)

func xml2json() {
    xml := `<testsuite tests="2" failures="0" time="0.009" name="github.com/subchen/go-xmldom">
    <testcase classname="go-xmldom" name="ExampleParseXML" time="0.004"></testcase>
    <testcase classname="go-xmldom" name="ExampleParse" time="0.005"></testcase>
</testsuite>`

    doc := xmldom.Must(xmldom.ParseXML(xml))
    root := doc.Root

    name := root.GetAttributeValue("name")
    time := root.GetAttributeValue("time")
    fmt.Printf("testsuite: name=%v, time=%v\n", name, time)

    for _node := range root.GetChildren("testcase") {
        name := node.GetAttributeValue("name")
        time := node.GetAttributeValue("time")
        fmt.Printf("testcase: name=%v, time=%v\n", name, time)
    }
}


んで、テストになってないテストプログラム

package xml2json

import "testing"

func TestXml2JSON(t *testing.T) {
    xml2json()
}



go test -vで動かすと以下の様に出てくる

=== RUN   TestXml2JSON

testsuite: name=github.com/subchen/go-xmldom, time=0.009

testcase: name=ExampleParseXML, time=0.004

testcase: name=ExampleParse, time=0.005

--- PASS: TestXml2JSON (0.00s)

PASS

ok      xml2json        0.004s





0 件のコメント: