C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[8]: XMLファイルの読み込みについて


(過去ログ 48 を表示中)

[トピック内 18 記事 (1 - 18 表示)]  << 0 >>

■26196 / inTopicNo.1)  XMLファイルの読み込みについて
  
□投稿者/ あゆみ (1回)-(2008/10/03(Fri) 15:34:18)

分類:[C#] 

はじめまして。
下記のようなXMLファイルの編集ソフトを考えています。(開発言語 C# VisualStudio2008)

@XMLファイルを読み込みテキストボックスに /email の中身をテキストボックス表示
A編集されたテキストボックス内の値で、XMLファイルを更新

XmlDocumentオブジェクトを使用して読み書きを行っているのですが
BBB.dtdファイルがないためエラーになってしまします。
そこで、BBB.dtdを適当な形で作成して読み込むとエンティティ &value; が展開されてしまいます。
XMLファイルはテンプレートなので、BBB.dtdがなくてもエラーにせず、&value;を展開せずに読み書きを行いたいと考えています。
XmlDocumentのオプションなどを設定する事で解決可能なのでしょうか?
ヘルプ等色々見てみたのですが解決策が見つからなかったため、
どなたかご教授願えないでしょうか。

【XMLの中身】
<?xml version="1.0" encoding="shift_jis" standalone="no" ?>
<!DOCTYPE email SYSTEM "BBB.dtd">
<email>値は&value;です。</email>


引用返信 編集キー/
■26204 / inTopicNo.2)  Re[1]: XMLファイルの読み込みについて
□投稿者/ Streetw♪ (1回)-(2008/10/03(Fri) 17:27:49)
No26196 (あゆみ さん) に返信
> XMLファイルはテンプレートなので、BBB.dtdがなくてもエラーにせず、&value;を展開せずに読み書きを行いたいと考えています。

こんにちは。
dtdがなくてもエラーにしない方法ですが、
Loadする前にXmlResolverプロパティにnullを設定するといいみたいです。

&value;の方はわかりません。
<email>値は&amp;value;です。</email>
だと大丈夫ですが。。

引用返信 編集キー/
■26264 / inTopicNo.3)  Re[2]: XMLファイルの読み込みについて
□投稿者/ あゆみ (2回)-(2008/10/06(Mon) 09:26:48)
Streetw♪様返信ありがとうございます。
XmlDocumentのXmlResolverプロパティをnullにしてみたのですが、
Loadの所で下記のエラーが表示されてしまいました。
他に何か回避策などはあれがご教授願います。

宣言されていないエンティティ '○○○' への参照です。

引用返信 編集キー/
■26267 / inTopicNo.4)  Re[3]: XMLファイルの読み込みについて
□投稿者/ Streetw♪ (2回)-(2008/10/06(Mon) 10:13:51)
No26264 (あゆみ さん) に返信
> XmlDocumentのXmlResolverプロパティをnullにしてみたのですが、
> Loadの所で下記のエラーが表示されてしまいました。
> 他に何か回避策などはあれがご教授願います。
>
> 宣言されていないエンティティ '○○○' への参照です。


ごめんなさい。実態参照のことをよく知らずに返信してました;
調べたところ、実態参照はdtdの中で宣言されてるんですね。
「エラーにせずに展開しない」の意味が今わかりました。。。

最悪、XMLで標準に定義されてる下の実態参照以外の「&」を一度「&amp;」に
置き換えるという事前処理をすればいいでしょうけど、他に方法がないか調べてみます。
他の方も、よろしくお願いします。。

&amp;
&lt;
&gt;
&quot;
&apos;
引用返信 編集キー/
■26270 / inTopicNo.5)  Re[4]: XMLファイルの読み込みについて
□投稿者/ Streetw♪ (3回)-(2008/10/06(Mon) 12:00:34)
↓これでできました!

private void button1_Click(object sender, EventArgs e)
{
    var doc = new XmlDocument();

    using (var reader = new MyXmlTextReader("test.xml"))
    {
        reader.XmlResolver = null;
        doc.Load(reader);
    }

    MessageBox.Show(doc.OuterXml);
}

private class MyXmlTextReader : XmlTextReader
{
    public MyXmlTextReader(string url)
        : base(url)
    {
    }

    public override void ResolveEntity()
    {
        // 解決しない
    }
}

引用返信 編集キー/
■26272 / inTopicNo.6)  Re[1]: XMLファイルの読み込みについて
□投稿者/ aetos(旧シャノン) (16回)-(2008/10/06(Mon) 12:18:49)
No26196 (あゆみ さん) に返信
> XMLファイルはテンプレートなので、BBB.dtdがなくてもエラーにせず、&value;を展開せずに読み書きを行いたいと考えています。

ということは、これは XML ファイルではないということになりませんかね。
XML ファイル以前のものを XML として読もうとするのが間違いではないでしょうか。
引用返信 編集キー/
■26277 / inTopicNo.7)  Re[2]: XMLファイルの読み込みについて
□投稿者/ あゆみ (3回)-(2008/10/06(Mon) 13:42:27)
>Streetw♪様

サンプルまで頂きまして誠にありがとうございます。
ただ、頂いたサンプルですと複数のノードが存在する場合に動作がおかしくなるようです。
特に XmlNode node = doc.SelectSingleNode("/email/b"); を実行するとエラーになってノードが
取得できなくなってしまいました。

【test.xml】
<?xml version="1.0" encoding="shift_jis" standalone="no" ?>
<!DOCTYPE email SYSTEM "BBB.dtd">
<email>
<aa>aの値は&valueA;です。</aa>
<b>bの値は&valueB;です。</b>
</email>

【プログラム】
private void button1_Click(object sender, EventArgs e) {
var doc = new XmlDocument();

using (var reader = new MyXmlTextReader("test.xml")) {
reader.XmlResolver = null;
doc.Load(reader);
}

XmlNode node = doc.SelectSingleNode("/email/b");
MessageBox.Show(node.InnerXml);

}

private class MyXmlTextReader : XmlTextReader {
public MyXmlTextReader(string url)
: base(url) {
}

public override void ResolveEntity() {
// 解決しない
}
}


>aetos(旧シャノン)様
返信ありがとうございます。
実現したいこととしては、エンティティが格納されたXMLファイルをあらかじめ作成しておきます。
そこにプログラムでエンティティファイルを動的に作成し、XMLファイルを読み込む処理を行いたいのです。
そこで、エンティティがない状態でユーザーにXMLファイルの編集を行わせたいと考えてます。
私もXML自体詳しいわけではないのですが、エンティティの展開やXMLの検証を行わないだけで
XMLファイルなるのでは?と思っていたのですが間違えなのでしょうか…



みなさん、いろいろお力を貸していただきましてありがとうございます。
私の方で調べてみたのですが、下記のようにDTDがある場合は XmlNode.InnerXml で
エンティティ展開前の値が取得できました。
なので、 doc.Load("test.xml"); でDTDがない場合にエラーが発生するのを防げば解決できそうなのですが…

【test.xml】
<?xml version="1.0" encoding="shift_jis" standalone="no" ?>
<!DOCTYPE email SYSTEM "BBB.dtd">
<email>
<aa>aの値は&valueA;です。</aa>
<b>bの値は&valueB;です。</b>
</email>

【BBB.dtd】
<?xml version="1.0" encoding="shift_jis" ?>
<!ENTITY valueA "AAA">
<!ENTITY valueB "BBB">

【プログラム】
private void button1_Click(object sender, EventArgs e) {
XmlDocument doc = new XmlDocument();
doc.Load("test.xml");
XmlNode node = doc.SelectSingleNode("/email/b");
MessageBox.Show(node.InnerXml);
}

引用返信 編集キー/
■26281 / inTopicNo.8)  Re[3]: XMLファイルの読み込みについて
□投稿者/ Streetw♪ (4回)-(2008/10/06(Mon) 14:56:51)
No26277 (あゆみ さん) に返信
> >Streetw♪様
>
> サンプルまで頂きまして誠にありがとうございます。
> ただ、頂いたサンプルですと複数のノードが存在する場合に動作がおかしくなるようです。
> 特に XmlNode node = doc.SelectSingleNode("/email/b"); を実行するとエラーになってノードが
> 取得できなくなってしまいました。


あ、私のは、実態参照の解決のところだけをしないんじゃなくって、
実態参照のところで中断されちゃうようです。失礼しました。。。
ResolveEntityを適切に実装するといいのかなと思ったので調べたんですが、
難しそうでよくわかりません。。



> 私の方で調べてみたのですが、下記のようにDTDがある場合は XmlNode.InnerXml で
> エンティティ展開前の値が取得できました。
> なので、 doc.Load("test.xml"); でDTDがない場合にエラーが発生するのを防げば解決できそうなのですが…


それ、私も午前中に考えてました。
けど、DTDがないと!ENTITYの定義もないので、対象のXMLの!DOCTYPEのところを変更するしかないかなとかも考えてました。

時間ができたらResolveEntityをもう少し調べます。
でも、だれか助けて・・・
引用返信 編集キー/
■26289 / inTopicNo.9)  Re[3]: XMLファイルの読み込みについて
□投稿者/ 中村家 (3回)-(2008/10/06(Mon) 16:17:17)
こんにちは、中村家といいます。

aetosさんでは無いですが、横槍失礼します。

■No26277 (あゆみ さん) に返信
> >aetos(旧シャノン)様
> 返信ありがとうございます。
> 実現したいこととしては、エンティティが格納されたXMLファイルをあらかじめ作成しておきます。
> そこにプログラムでエンティティファイルを動的に作成し、XMLファイルを読み込む処理を行いたいのです。
> そこで、エンティティがない状態でユーザーにXMLファイルの編集を行わせたいと考えてます。

・エンティティが含まれるXMLファイルが存在する。
・エンティティ定義ファイル(DTD)をユーザにPGを通して作成させたい

上記を実現したいんですよね?
loadする前にDTDを作成してしまえば良いだけのような気がします。
後は、確定したDTDでloadすれば良いだけで。

エラーを単純に無視したいということであれば、

XMLDocumentオブジェクトを利用せず、
XmlTextReaderオブジェクトで読込めば良いかと思います。
#うろ覚えですが、整形式なXMLであればDTD無くともエンティティ展開せずに読めたかと思いました。

引用返信 編集キー/
■26297 / inTopicNo.10)  Re[4]: XMLファイルの読み込みについて
□投稿者/ Streetw♪ (5回)-(2008/10/06(Mon) 17:10:05)
危険な方法でできました・・・
aetosさんや中村家さんの方が正しいヤリだと思います。

var doc = new XmlDocument();

using (var reader = new XmlTextReader("test.xml"))
{
    reader.XmlResolver = null;

    // 未定義のエンティティがあってもエラーにしません!
    // Frameworkの内部実装にとっても依存・・・
    {
        var fieldInfo =
            reader.GetType().GetField(
                "impl",
                BindingFlags.Instance | BindingFlags.NonPublic);
        var impl = fieldInfo.GetValue(reader);

        var propertyInfo =
            impl.GetType().GetProperty(
                "DisableUndeclaredEntityCheck",
                BindingFlags.Instance | BindingFlags.NonPublic);
        propertyInfo.SetValue(impl, true, null);
    }

    doc.Load(reader);
}

XmlNode node = doc.SelectSingleNode("/email/b");
MessageBox.Show(node.InnerXml);

引用返信 編集キー/
■26314 / inTopicNo.11)  Re[4]: XMLファイルの読み込みについて
□投稿者/ れい (809回)-(2008/10/06(Mon) 21:09:49)
No26267 (Streetw♪ さん) に返信
> 調べたところ、実態参照はdtdの中で宣言されてるんですね。

ろくに読んでないですが、情報密度維持のために。
「実態」ではなく「実体」です。
実体参照。

引用返信 編集キー/
■26327 / inTopicNo.12)  Re[2]: XMLファイルの読み込みについて
□投稿者/ れい (810回)-(2008/10/07(Tue) 08:07:51)
> ■No26196 (あゆみ さん) に返信
>>XMLファイルはテンプレートなので、BBB.dtdがなくてもエラーにせず、&value;を展開せずに読み書きを行いたいと考えています。
> 
> ということは、これは XML ファイルではないということになりませんかね。
> XML ファイル以前のものを XML として読もうとするのが間違いではないでしょうか。

この辺気になったので調べてみました。
「Extensible Markup Language (XML) 1.0 (Fourth Edition)」 (http://www.w3.org/TR/REC-xml/)の
「4.1 Character and Entity References」に
---
Well-formedness constraint: Entity Declared

In a document without any DTD, a document with only an internal DTD subset which contains no parameter entity references, or a document with "standalone='yes'", for an entity reference that does not occur within the external subset or a parameter entity, the Name given in the entity reference MUST match that in an entity declaration that does not occur within the external subset or a parameter entity, except that well-formed documents need not declare any of the following entities: amp, lt, gt, apos, quot. The declaration of a general entity MUST precede any reference to it which appears in a default value in an attribute-list declaration.

Note that non-validating processors are not obligated to to read and process entity declarations occurring in parameter entities or in the external subset; for such documents, the rule that an entity must be declared is a well-formedness -constraint only if standalone='yes'.
---
とあります。
standalone='no'となっていれば、使用されている実体参照が宣言されていなくてもwell-formedのようです。

また、「5.2 Using XML Processors」には、
---
Certain well-formedness errors, specifically those that require reading external entities, may fail to be detected by a non-validating processor. Examples include the constraints entitled Entity Declared, Parsed Entity, and No Recursion, as well as some of the cases described as forbidden in 4.4 XML Processor Treatment of Entities and References.
---
とも書かれています。

つまり。
---
<?xml version="1.0" encoding="shift_jis" standalone="no" ?>
<!DOCTYPE email SYSTEM "BBB.dtd">
<email>値は&value;です。</email>
---
こんなxmlはBBB.dtdが存在する/しない、正しい/正しくないに関わらず「整形式」で、
BBB.dtdが存在しなかったり正しくない場合にXmlProcessorがエラーを吐くかどうかはSpecificationでは定義されてない、
実体参照がどう展開されるかも定義されていない、
ということになります。

現実に使う身としては、BBB.dtdが実際には存在しなかったり変でも、
整形式としては読めるようなオプションが欲しいところです。

で、中村家 さんが言うように、
■No26289 (中村家 さん) に返信
> XMLDocumentオブジェクトを利用せず、
> XmlTextReaderオブジェクトで読込めば良いかと思います。
> #うろ覚えですが、整形式なXMLであればDTD無くともエンティティ展開せずに読めたかと思いました。

XmlTextReaderで、XmlResolver=nullとすれば参照を解決せずに読むことが可能でした。
(XmlReaderSetting.XmlResolver=nullとしてXmlReader.CreateしたXmlReaderでは、例外)

XmlResolver=nullなXmlTextReader経由でXmlDocumentに読もうとしても

■No26264 (あゆみ さん) に返信
> Loadの所で下記のエラーが表示されてしまいました。
> 
> 宣言されていないエンティティ '○○○' への参照です。
これと同じで例外になりました。

.NetのXmlParserは標準では
・XmlTextReaderはnullにすればエンティティが無い場合でも読める
・XmlReader.Createだとエンティティが無い場合は読めない
・XmlDocumentはエンティティが無い場合は読めない
となっているようです。

しょうがないのでStreetw♪さんに倣い、ResolveEntityを上書きしたクラスを作ってみました。
これであゆみさんのあげたxmlならばdtdを読まずにXmlDocumentに読み込めます。
適当に作ってますので、多様なxmlに対応するためにはたぶん細かい点を修正する必要があります。

----
    Public Class MyXmlReader
        Inherits Xml.XmlReader
        Private _innerreader As Xml.XmlReader
        Private _state As Integer
        Private _entityname As String

        Public Sub New(ByVal filename As String)
            _innerreader = New Xml.XmlTextReader(filename)
            _state = 0
        End Sub

        Public Overrides ReadOnly Property CanResolveEntity() As Boolean
            Get
                Return True
            End Get
        End Property

        Public Overrides Sub ResolveEntity()
            If _innerreader.NodeType <> Xml.XmlNodeType.EntityReference Then Throw New InvalidOperationException
            _entityname = _innerreader.Name
            _state = 1
        End Sub

        Public Overrides Function Read() As Boolean
            Select Case _state
                Case 1
                    _state = 2
                    Return True
                Case 2
                    _state = 3
                    Return True
                Case Else
                    _state = 0
                    Return _innerreader.Read
            End Select
        End Function

        Public Overrides ReadOnly Property Value() As String
            Get
                If _state = 2 Then Return _entityname
                Return _innerreader.Value
            End Get
        End Property

        Public Overrides ReadOnly Property NodeType() As System.Xml.XmlNodeType
            Get
                Select Case _state
                    Case 2
                        Return Xml.XmlNodeType.Text
                    Case 3
                        Return Xml.XmlNodeType.EndEntity
                    Case Else
                        Return _innerreader.NodeType
                End Select
            End Get
        End Property

        Public Overrides ReadOnly Property HasValue() As Boolean
            Get
                If _state = 2 Then Return True
                Return _innerreader.HasValue
            End Get
        End Property


	'以下は単純なラッパー

        Public Overrides Sub Close()
            _innerreader.Close()
        End Sub

        Public Overrides ReadOnly Property AttributeCount() As Integer
            Get
                Return _innerreader.AttributeCount
            End Get
        End Property

	'略

    End Class
----

ただ、
> &value;を展開せずに読み書きを行いたいと考えています。
というのを実現するだけなら、
ダミーのdtdを用いてLoadするだけでいいはずです。

NodeType=EntityReferenceなNodeがDOMの中に生成されますし、
自分でEntityReferenceなNodeをDOM中に生成することも可能です。
後でdtdを差し替えるのに何も問題ありません。

引用返信 編集キー/
■26331 / inTopicNo.13)  Re[3]: XMLファイルの読み込みについて
□投稿者/ Streetw♪ (6回)-(2008/10/07(Tue) 11:21:35)
No26327 (れい さん) に返信
> 「実態」ではなく「実体」です。
> 実体参照。

Σあ、失礼しました〜
どうもです。


> standalone='no'となっていれば、使用されている実体参照が宣言されていなくてもwell-formedのようです。

へぇ〜×3。
内部にはDisableUndeclaredEntityCheckというフラグがあるのに公開されてないのは、
XMLの規格に準拠するためかな?って思ったんですが、違うんですね。
じゃ、公開してくれたらいいのに。。

れいさんのコードを使えば、実体参照の解決(展開?)を独自実装できるから、何かに使えそうですね!
最初からイベントになってればいいのにって思いました。

ちょっと試してみよっと思ってコードを貼り付けたら、「以下は単純なラッパー」のところにたくさん
コードが自動的に追加されたの見て、試すの迷い中・・・;
引用返信 編集キー/
■26339 / inTopicNo.14)  Re[4]: XMLファイルの読み込みについて
□投稿者/ れい (811回)-(2008/10/07(Tue) 13:39:43)
No26331 (Streetw♪ さん) に返信
> れいさんのコードを使えば、実体参照の解決(展開?)を独自実装できるから、何かに使えそうですね!
> 最初からイベントになってればいいのにって思いました。

参照の解決だけイベントってのは変なので、
イベントを起こすなら、タグなどの各種要素でもイベントを起こすことになるはずです。

でも、それをやっちゃったらSAXです。
XmlReaderはプッシュではなく、プルで実装してますので、
「イベントになってればいい」、というなら「SAXでいいじゃん」ということになってしまって、
XmlReaderの存在意義の否定になっちゃいます。

というわけで、イベントはダメです。

#SAXのようなプッシュではなく、プルで実装されてる理由は
#http://msdn.microsoft.com/ja-jp/library/sbw89de7(VS.80).aspx
#この辺に書いてあります。

ただ、ドキュメントをもっときちんと書いて欲しいと思いました。
独自実装するにはつらいです。
ResolveEntityに関して言えば

> リーダーが EntityReference ノード (XmlNodeType.EntityReference) に配置されている場合は、このメソッドを呼び出した後に Read を呼び出すと、エンティティ置換テキストが解析されます。エンティティ置換テキストが完成すると、EndEntity ノードが返され、エンティティ参照スコープを閉じます。

これだけの情報しかありません…
あとは作成者の心を読むしか。
引用返信 編集キー/
■26342 / inTopicNo.15)  Re[5]: XMLファイルの読み込みについて
□投稿者/ なちゃ (176回)-(2008/10/07(Tue) 14:38:34)
別に存在意義の否定にはならないと思いますが…
プッシュ型に変えてしまえば別ですけど、プル型ってことと
イベントを提供するってことは別に矛盾しませんよね?

引用返信 編集キー/
■26372 / inTopicNo.16)  Re[6]: XMLファイルの読み込みについて
□投稿者/ れい (812回)-(2008/10/07(Tue) 22:11:50)
No26342 (なちゃ さん) に返信
> 別に存在意義の否定にはならないと思いますが…
> プッシュ型に変えてしまえば別ですけど、プル型ってことと
> イベントを提供するってことは別に矛盾しませんよね?

そうですか?
一般的な意味ではプルとイベントは両立しないと思いますが。

無理に両立したクラスを設計することもできるでしょうが、
使いづらいことが用意に想像できますし、実際そんなクラスはあまりないですよね。

まぁそれだけの話です。
引用返信 編集キー/
■26374 / inTopicNo.17)  Re[7]: XMLファイルの読み込みについて
□投稿者/ なちゃ (177回)-(2008/10/07(Tue) 23:19:44)
No26372 (れい さん) に返信
> そうですか?
> 一般的な意味ではプルとイベントは両立しないと思いますが。
>
> 無理に両立したクラスを設計することもできるでしょうが、
> 使いづらいことが用意に想像できますし、実際そんなクラスはあまりないですよね。

うーん、一般的なってどういうのか分かりませんが、
別にイベントのトリガがプルのタイミング(かつプルの対象、まあそれだけとは限れないかもしれませんが)
になるってくらいのものしか想定してないです。

今回のような、特定の処理部分に対して特別にイベントを提供するだけ、
というのは別にありえないというほどの話じゃないんでは?てことです。

まあ、「最初からイベントになってればいいのにって思いました。」に対して、
> 参照の解決だけイベントってのは変なので、
> イベントを起こすなら、タグなどの各種要素でもイベントを起こすことになるはずです。
> でも、それをやっちゃったらSAXです。
ってちょっと極端かなって感じただけです。
※処理の考え方や方式を根本的に変えるレベルまでいかないとできない話、というわけではないんじゃないかと

引用返信 編集キー/
■26379 / inTopicNo.18)  Re[8]: XMLファイルの読み込みについて
□投稿者/ れい (813回)-(2008/10/08(Wed) 00:19:08)
No26374 (なちゃ さん) に返信
> まあ、「最初からイベントになってればいいのにって思いました。」に対して、
> > 参照の解決だけイベントってのは変なので、
> > イベントを起こすなら、タグなどの各種要素でもイベントを起こすことになるはずです。
> > でも、それをやっちゃったらSAXです。
> ってちょっと極端かなって感じただけです。
> ※処理の考え方や方式を根本的に変えるレベルまでいかないとできない話、というわけではないんじゃないかと

言い方は極端ですが。
プル型にイベントを混ぜるのは処理の考え方を根本的に変えるレベルだと思います。

XmlReaderの場合、SAXとの区別、差別化をしないといけない時代的都合がありますし、
.Netは汎用のフレームワークで、XML周りの処理は時代的に重要な部分だったはずで、
そういったことを考えると、
「プル型のクラスだけど、ちょこっと、特別な部分だけ、イベントを使っちゃいましょう」
という設計は、.NetのXmlReaderの設計としてはありえないと思ってます。

まぁ各種資料から作成者の意図を私が類推してるだけですので、
本当のところは実際に作った人に聞いてください。

フレームワーク設計の「ありえる・ありえない」の話(=べき論)は経験が如実に現れる部分で、議論は面白いと思いますが、
ここでやると話題がずれてしまいますし、たぶん長くなります。

ここでは、
なちゃ さんは「別にあってもよかった」
私は「もう全然全くありえない」
という判断をしているということを確認した、という所までで、
つづきの議論は別項や、またの機会に。
ってことでどうでしょう?
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -