|
> ■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を差し替えるのに何も問題ありません。
|