LoginSignup
0
0

More than 1 year has passed since last update.

Parsrsのconvx2j.shのバグを見つけた気がしたが、ひょっとしたら仕様外かもしれなかった。

Posted at

概要

  • XMLをJSONに変換する用のツールがある。
    • 中間表現を介するやつ。
  • 変換過程でバグがあると思ったが、ひょっとしたら使われるXMLが想定外の形式だったかもしれない。
  • 構造化データではなくマークアップそのものだったら想定外かも

Parsrsとは

ShellShoccar-jpn/Parsrsというユーティリティ。

使用したバージョン

$ awk -v cmds='parsrx.sh convx2j.sh makrj.sh parsrj.sh' 'BEGIN{split(cmds,a);for(i in a){printf("echo %s; %s --version 2>&1 | grep -F Version\n", a[i], a[i]);}}' | sh
parsrx.sh
Version : 2022-02-06 12:45:01 JST
convx2j.sh
Version : 2020-05-06 22:42:19 JST
makrj.sh
Version : 2022-02-04 18:33:13 JST
parsrj.sh
Version : 2022-02-06 01:34:22 JST

引用したXMLのファイル

WikipediaのDocBookの項目からDocBookのサンプルファイルを。
2022年11月の版。

sample.docbook
<?xml version="1.0" encoding="UTF-8"?>
 <book xml:id="simple_book" xmlns="http://docbook.org/ns/docbook" version="5.0">
   <title>Very simple book</title>
   <chapter xml:id="chapter_1">
     <title>Chapter 1</title>
     <para>Hello world!</para>
     <para>I hope that your day is proceeding <emphasis>splendidly</emphasis>!</para>
   </chapter>
   <chapter xml:id="chapter_2">
     <title>Chapter 2</title>
     <para>Hello again, world!</para>
   </chapter>
 </book>

TLDR

$ cat sample.docbook 
<?xml version="1.0" encoding="UTF-8"?>
 <book xml:id="simple_book" xmlns="http://docbook.org/ns/docbook" version="5.0">
   <title>Very simple book</title>
   <chapter xml:id="chapter_1">
     <title>Chapter 1</title>
     <para>Hello world!</para>
     <para>I hope that your day is proceeding <emphasis>splendidly</emphasis>!</para>
   </chapter>
   <chapter xml:id="chapter_2">
     <title>Chapter 2</title>
     <para>Hello again, world!</para>
   </chapter>
 </book>
$ parsrx.sh -c -n sample.docbook 
/book[1]/@xml:id simple_book
/book[1]/@xmlns http://docbook.org/ns/docbook
/book[1]/@version 5.0
/book[1]/title[1] Very simple book
/book[1]/chapter[1]/@xml:id chapter_1
/book[1]/chapter[1]/title[1] Chapter 1
/book[1]/chapter[1]/para[1] Hello world!
/book[1]/chapter[1]/para[2]/emphasis[1] splendidly
/book[1]/chapter[1]/para[2] I hope that your day is proceeding <emphasis/>!
/book[1]/chapter[1] \n    <title/>\n    <para/>\n    <para/>\n  
/book[1]/chapter[2]/@xml:id chapter_2
/book[1]/chapter[2]/title[1] Chapter 2
/book[1]/chapter[2]/para[1] Hello again, world!
/book[1]/chapter[2] \n    <title/>\n    <para/>\n  
/book[1] \n  <title/>\n  <chapter/>\n  <chapter/>\n
$ parsrx.sh -c -n sample.docbook | convx2j.sh 
$.book.@xml:id simple_book
$.book.@xmlns http://docbook.org/ns/docbook
$.book.@version 5.0
$.book.title Very simple book
$.book.chapter[0].@xml:id chapter_1
$.book.chapter[0].title Chapter 1
$.book.chapter[0].para Hello world!
$.book.chapter[0].para[1].emphasis splendidly
$.book.chapter[1].@xml:id chapter_2
$.book.chapter[1].title Chapter 2
$.book.chapter[1].para Hello again, world!
$ parsrx.sh -c -n sample.docbook | convx2j.sh | makrj.sh 
{
"book":{
"@xml:id":"simple_book",
"@xmlns":"http://docbook.org/ns/docbook",
"@version":5.0,
"title":"Very simple book",
"chapter":[{
"@xml:id":"chapter_1",
"title":"Chapter 1",
"para":"Hello world!"[{
"emphasis":"splendidly"
}]
},{
"@xml:id":"chapter_2",
"title":"Chapter 2",
"para":"Hello again, world!"
}]
}
}
$ parsrx.sh -c -n sample.docbook | convx2j.sh | makrj.sh | parsrj.sh 
$.book.@xml:id simple_book
$.book.@xmlns http://docbook.org/ns/docbook
$.book.@version 5.0
$.book.title Very simple book
$.book.chapter[0].@xml:id chapter_1
$.book.chapter[0].title Chapter 1
$.book.chapter[0].para Hello world!
Invalid JSON format
keyname-stack:{book}{chapter}{0}{para}
$ 

convx2j.shのヘッダコメントにて「プリプロセッサとしてparsrx.sh -c -nが必要」と記載。parsrx.shはXMLファイルを解析して行指向テキストに変換するコマンド。-cで「値内の子タグを明確に出力(このフラグがなければタグ内の値に子タグがあたかもなかったかのように表示。要は<parent>a<em>B</em>c</parent>に対し、/parent acと表示されていたのを/parent a<em/>cと表示するようにする)」、-nで「タグに番号を付けて表示」、という仕様。そんでもってconvx2j.shでXMLの中間表記をJSONの中間表記に変換する。

それでmakrj.shでJSONに変換できる。
そしてparsrj.shでもう一度パーズできる。

はずだった。

情報が落ちた。

parsrx.sh -ncしたのと、convx2j.shもしたのとで出力を比較。

parsrx.sh -nc convx2j.sh
/book[1]/@xml:id simple_book $.book.@xml:id simple_book
/book[1]/@xmlns http://docbook.org/ns/docbook $.book.@xmlns http://docbook.org/ns/docbook
/book[1]/@version 5.0 $.book.@version 5.0
/book[1]/title[1] Very simple book $.book.title Very simple book
/book[1]/chapter[1]/@xml:id chapter_1 $.book.chapter[0].@xml:id chapter_1
/book[1]/chapter[1]/title[1] Chapter 1 $.book.chapter[0].title Chapter 1
/book[1]/chapter[1]/para[1] Hello world! $.book.chapter[0].para Hello world!
/book[1]/chapter[1]/para[2]/emphasis[1] splendidly $.book.chapter[0].para[1].emphasis splendidly
/book[1]/chapter[1]/para[2] I hope that your day is proceeding <emphasis/>!
/book[1]/chapter[1] \n <title/>\n <para/>\n <para/>\n
/book[1]/chapter[2]/@xml:id chapter_2 $.book.chapter[1].@xml:id chapter_2
/book[1]/chapter[2]/title[1] Chapter 2 $.book.chapter[1].title Chapter 2
/book[1]/chapter[2]/para[1] Hello again, world! $.book.chapter[1].para Hello again, world!
/book[1]/chapter[2] \n <title/>\n <para/>\n
/book[1] \n <title/>\n <chapter/>\n <chapter/>\n

なんと、/book[1]/chapter[1]/para[2] I hope that your day is proceeding <emphasis/>!の情報が落ちているではないか。
というのも、/book[1]/chapter[2]/para[2]がないからである。
最初の<chapter>には<para>が二つもあったが二つ目の<chapter>には<para>が一つしかない。
これが、原因だったか。

よって、$.book.chapter[0].paraの次の行は$.book.chapter[0].para[1].emphasisが来ており、これをmakrj.shによりJSONに変換すると文法として誤ったものになった。

誤ったJSON
{
"book":{
"@xml:id":"simple_book",
"@xmlns":"http://docbook.org/ns/docbook",
"@version":5.0,
"title":"Very simple book",
"chapter":[{
"@xml:id":"chapter_1",
"title":"Chapter 1",
"para":"Hello world!"[{ # ここが文法誤りの結果
"emphasis":"splendidly"
}]
},{
"@xml:id":"chapter_2",
"title":"Chapter 2",
"para":"Hello again, world!"
}]
}
}

まず例のユーティリティは「構造化データをJSONにする」のであり、正直言って「マークアップされた文書をJSONにする」のではないんだろう、きっと。

他の「XMLをJSONに変換するツール」とも比較

JSON formatterのXML to JSON

こう出力された。

{
	"book": {
		"title": "Very simple book",
		"chapter": [
			{
				"title": "Chapter 1",
				"para": [ # 配列として出力
					"Hello world!",
					{ # <emphasis>の値と<emphasis>を除いたものになってる
						"emphasis": "splendidly",
						"__text": "I hope that your day is proceeding \n!"
					}
				],
				"_xml:id": "chapter_1"
			},
			{
				"title": "Chapter 2",
				"para": "Hello again, world!", # 文字列として出力
				"_xml:id": "chapter_2"
			}
		],
		"_xmlns": "http://docbook.org/ns/docbook",
		"_xml:id": "simple_book",
		"_version": "5.0"
	}
}

Code BeautyのXML to JSON Converter

__text#textであることを除き、同様だった。

{
  "book": {
    "title": "Very simple book",
    "chapter": [
      {
        "title": "Chapter 1",
        "para": [
          "Hello world!",
          {
            "#text": "I hope that your day is proceeding!",
            "emphasis": "splendidly"
          }
        ]
      },
      {
        "title": "Chapter 2",
        "para": "Hello again, world!"
      }
    ]
  }
}

ConvertJson.comのXML To JSON Converter

同様だしここに載せるのも飽きた。

{
   "book": {
      "title": "Very simple book",
      "chapter": [
         {
            "title": "Chapter 1",
            "para": [
               "Hello world!",
               {
                  "emphasis": "splendidly",
                  "__text": "I hope that your day is proceeding \n!"
               }
            ],
            "_xml:id": "chapter_1"
         },
         {
            "title": "Chapter 2",
            "para": [
               "Hello again, world!"
            ],
            "_xml:id": "chapter_2"
         }
      ],
      "_xmlns": "http://docbook.org/ns/docbook",
      "_xml:id": "simple_book",
      "_version": "5.0"
   }
}

まとめ

XMLをJSONに変換する目的って正直言って、「構造化データをJSONに変換する」ためなんだけど、XMLってマークアップに使う場合もあるよね。
世の中の「XMLをJSONに変換するツール」は、よくできているものだなと思った。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0