- PR -

byte配列をXmlReaderで読み込み

1
投稿者投稿内容
sk
会議室デビュー日: 2007/09/26
投稿数: 4
投稿日時: 2007-09-26 19:16
C#で、テキストファイルを読み込んでXMLデータを一旦byte配列に格納した後、byte配列をXMLデータに変換する処理をしようと思っているのですが、うまくいかず困っています。

以下にソースコード(一部)と読み込み元のXMLファイルを示します。


------------------------------------------------------------------

◆ソースコード

string file_path = "booksSchemaValid.xml";
byte[] targetXML = new byte[1024];
FileStream fs = File.OpenRead(file_path);
UTF8Encoding temp = new UTF8Encoding(true);
fs.Read(targetXML, 0, targetXML.Length);
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
XmlReader reader = XmlReader.Create(s, settings);



◆XMLファイル:booksSchemaValid.xml

<?xml version='1.0'?>
<bookstore>
<book>
<title>The Confidence Mans</title>
<author>
<first-name>Benjamin</first-name>
<last-name>Franklin</last-name>
</author>
<price>200.99</price>
</book>
<book genre="novel">
<title>The Confidence Man</title>
<author>
<first-name>Herman</first-name>
<last-name>Melville</last-name>
</author>
<price>11.99</price>
</book>
<book genre="philosophy">
<title>The Gorgias</title>
<author>
<first-name>Plato</first-name>
<last-name>Plato</last-name>
</author>
<price>9.99</price>
</book>
</bookstore>

------------------------------------------------------------------

readerから内容を出力しようとしても、出力されません。(エラーも出ません)
どなかたご教授願えないでしょうか?
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2007-09-26 22:05
ちと削りすぎですね。temp が浮いているし、XmlReader.Create の第一引数 s が不明。
あと、なんでそういうことをしようかと言うところを説明すると意外な解決がもたらされるかもしれませんよ。このままのコードなら byte[] で受ける意味がまったくありませんから、なにか目的があるのでしょう?

// 1024 バイト固定じゃ整形式にならない気がするけど。
// Fragment の意味分かってるかな……。
sk
会議室デビュー日: 2007/09/26
投稿数: 4
投稿日時: 2007-09-27 09:42
確かに省略しすぎていました。
申し訳ありません。
目的を言いますと、byte[]のXMLデータを引数で受け取って、Xpathによるデータ抽出を行いと思っています。


以下、サンプルで作ったソースコードと実行結果です。
(byte[]のXMLデータを読み込むところまでの処理しか作っていません。
 本来はbyte配列のデータをもらうことになっていますが、サンプルではファイルからデータを読み込んでbyte配列に一旦格納するという冗長なことをやっています(テスト用に作っているので・・・))

---------------------------------------------------------------------------
class Program
{
    public string xPath = "/bookstore/book/author/first-name"; //取得先Xpath
public string file_path = "booksSchemaValid.xml";
const int READ_SIZE = 4096;
byte[] targetXML = new byte[READ_SIZE];

public static void Main(string[] args)
{
FileStream fs = File.OpenRead(file_path);
UTF8Encoding temp = new UTF8Encoding(true);
fs.Read(targetXML, 0, targetXML.Length);
      
      Sample.Extract(targetXML, xPath);
}
}

class Sample
{
public void static Extract(byte[] targetXML, string xPath)
{
MemoryStream s = new MemoryStream();
s.Write(targetXML, 0, targetXML.Length);
UTF8Encoding temp = new UTF8Encoding(true);
      //XmlReader インスタンスの作成
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
XmlReader reader = XmlReader.Create(s, settings);

if (reader.MoveToContent() == XmlNodeType.None)
Console.WriteLine("None");
}
}


【実行結果】
None

---------------------------------------------------------------------------



>// 1024 バイト固定じゃ整形式にならない気がするけど。
1024バイトは古いソースからとってきたものでした。
4096バイトです。

>// Fragment の意味分かってるかな……。
すみません。よく分かっていないです。


C#初心者なので、理解不十分なところが多々ありますが、
どうかご教授お願いいたします。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2007-09-27 12:45
MemoryStream には、byte[] を受け取るコンストラクタが用意されています。わざわざ Write する必要はありません。

引用:
コード:
XmlReader reader = XmlReader.Create(s, settings); 

    if (reader.MoveToContent() == XmlNodeType.None) 
    Console.WriteLine("None"); 
}



XmlReader は、Read メソッドが呼ばれるごとに次のノードに移動していきます。逆に言うと、Read を呼び出さない限り、XML を触りもしません。

目的が XPath の使用なら、XmlReader よりも XmlDocument の方が良いでしょう。こちらなら Load 一発です。
XmlReader を使ってもどうせ XPath 使うのに DOM を構築することになりますし。

引用:

>// 1024 バイト固定じゃ整形式にならない気がするけど。
1024バイトは古いソースからとってきたものでした。
4096バイトです。


もし、元データが配列サイズよりも大きい場合。XML は、当然のことながら開始タグに対応する終了タグが必須です。元データが配列より大きかった場合、はみ出た分は使われないわけで、恐らくタグの対応が失われることになります。
逆に元データが小さかった場合。.NET では、配列はゼロまたは null で初期化されるので、後ろはゼロが埋まります。UTF-8 にせよ UTF-16 にせよ(こっちは 2 バイト必要ですが)、0 は \u0000 として扱われますが、XML では \u0000 は使ってはいけない文字であり、かつルート要素の後ろにノードが来ている、二重に不正な XML と言うことになります。
// XmlDocument.Load では \u0000 は終端文字と見做されるのか通っちゃうようですが。

引用:

>// Fragment の意味分かってるかな……。
すみません。よく分かっていないです。


整形式の XML はルート要素が一つだけ必要ですが、Fragment はルート要素を持たない XML の断片です。
ルート要素を持たないと言っても、開始タグと終了タグの対応は必須です。
sk
会議室デビュー日: 2007/09/26
投稿数: 4
投稿日時: 2007-09-27 20:46
大変丁寧な御説明ありがとうございます。

>MemoryStream には、byte[] を受け取るコンストラクタが用意されています。わざわざ Write する必要はありません。

>目的が XPath の使用なら、XmlReader よりも XmlDocument の方が良いでしょう。こちらなら Load 一発です。

アドバイスをいただいたとおりに修正してみましたが、やはりうまくいきません。

以下が修正したコードです(メソッドExtractの内容のみ修正)。
---------------------------------------------------------------------------

class Sample
{
    public void static Extract(byte[] targetXML, string xPath)
    {
        MemoryStream s = new MemoryStream(targetXML, true);
        XmlDocument doc = new XmlDocument();
        doc.Load(s);
        XmlElement root = doc.DocumentElement;
        XmlElement e1 = (XmlElement)root.FirstChild;
        XmlElement e2 = (XmlElement)e1.NextSibling;

        Console.WriteLine("e1 is " + e1.FirstChild.Value);
        Console.WriteLine("e2 is " + e2.FirstChild.Value);
    }
}


【実行結果】
e1 is
e2 is

---------------------------------------------------------------------------


byte配列のサイズが問題なのでしょうか?
何が問題なのか正直見当もつかない状況です。

渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2007-09-27 21:09
引用:

何が問題なのか正直見当もつかない状況です。



XmlNode.Value のヘルプ読んでみたら?

特に、「プロパティ値」の表の Element の行を刮目して読むべし。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2007-09-27 21:50
つか XmlDocument なら直接 XPath を突っ込めるメソッドが用意されてるのですが。
// まあそっから先は XmlNode いじくることになるでしょうが。
sk
会議室デビュー日: 2007/09/26
投稿数: 4
投稿日時: 2007-09-28 09:32
無事解決しました!
単純に勉強不足が問題でした。。。

>Hongliang様、渋木宏明(ひどり)様
大変お世話になりました。本当にありがとうございました。

もっと勉強を重ねて精進したいと思います。
1

スキルアップ/キャリアアップ(JOB@IT)