WebBrowser上の<a>タグ内の属性を削除したい への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2012/3/22 23:18:57
System.Windows.Forms.HtmlDocument 等で示される DOM (ドキュメント オブジェクト モデル)は、
COM(ActiveX)版のDOM を、.NET から扱いやすくするためにカプセル化したものです。
COM 版の具体的な API 定義は、MSHTML というライブラリにまとめられています。
http://msdn.microsoft.com/en-us/library/aa741317.aspx
http://msdn.microsoft.com/en-us/library/Aa752574.aspx
http://msdn.microsoft.com/en-us/library/aa752574.aspx
しかし、.NET でのカプセル化は十分なものではないため、それを解消できるよう、
大本のアンマネージ インターフェイスにもアクセスできるような作りになっています。
具体的には、HtmlDocument クラスの DomDocument プロパティや
HtmlWindow クラスの DomWindow プロパティ、それに
HtmlHistory クラスの DomHistory プロパティが該当します。
もちろん、HtmlElement クラスの DomElement プロパティもそうですし、あるいは
WebBrowser コントロールの ActiveXInstance プロパティなどもこれに近い仕組みです。
> 変数を使い終わったらReleaseComObjectということをしているようですが
それは COM オブジェクトを使った後に、後始末として呼ぶメソッドですが、
サンプルコードをあまり複雑にすると本題部分が分かりにくくなるため、今回は記述していません。
ちなみに別スレッドに投稿した、アンマネージの createTextRange メソッドを呼び出すサンプルにて
http://rucio.cloudapp.net/CommentDetail.aspx?ThreadId=10769&CommentId=23111
あえてそのソースを「手抜き実装」と評していますが、これは、createTextRange で得たオブジェクトを
ReleaseComObject していないというのが、その発言理由の一つです。
(他にも、ページ遷移中に ListBox 操作された場合の対処漏れなどの「手抜き」があります)
とはいえ、無理に ReleaseComObject せずとも、「いずれは」ファイナライザにて
後始末が行われるわけですから、回収タイミングがシビアではないケースにおいては、
明示的に回収せず、ガベージコレクタに任せておくだけでも十分と言えます。
しかし、確保していたオブジェクトが占有性の高い資源であった場合は別です。
「いずれ」ではなく「使わなくなったら即時に」解放しないと、それらを他のプログラムが
利用できなくなってしまいますので、その場合はマネージかアンマネージかを問わず、
他で使われていないことが保証できた時点で、すぐに後始末しておいた方が良いでしょう。
また、解放順序が意味を持つようなオブジェクトの場合も、明示的に後処理すべきです。
具体例を挙げるなら、COM のアウトプロセスサーバー(Excel 等)へのアクセス時や、
短時間の間に連続して幾度も繰り返されし確保されるアンマネージリソースなどでしょうか。
あるいはデータベースやファイル操作、COMポート操作時なども、即時解放が望ましいでしょうね。
COM(ActiveX)版のDOM を、.NET から扱いやすくするためにカプセル化したものです。
COM 版の具体的な API 定義は、MSHTML というライブラリにまとめられています。
http://msdn.microsoft.com/en-us/library/aa741317.aspx
http://msdn.microsoft.com/en-us/library/Aa752574.aspx
http://msdn.microsoft.com/en-us/library/aa752574.aspx
しかし、.NET でのカプセル化は十分なものではないため、それを解消できるよう、
大本のアンマネージ インターフェイスにもアクセスできるような作りになっています。
具体的には、HtmlDocument クラスの DomDocument プロパティや
HtmlWindow クラスの DomWindow プロパティ、それに
HtmlHistory クラスの DomHistory プロパティが該当します。
もちろん、HtmlElement クラスの DomElement プロパティもそうですし、あるいは
WebBrowser コントロールの ActiveXInstance プロパティなどもこれに近い仕組みです。
> 変数を使い終わったらReleaseComObjectということをしているようですが
それは COM オブジェクトを使った後に、後始末として呼ぶメソッドですが、
サンプルコードをあまり複雑にすると本題部分が分かりにくくなるため、今回は記述していません。
ちなみに別スレッドに投稿した、アンマネージの createTextRange メソッドを呼び出すサンプルにて
http://rucio.cloudapp.net/CommentDetail.aspx?ThreadId=10769&CommentId=23111
あえてそのソースを「手抜き実装」と評していますが、これは、createTextRange で得たオブジェクトを
ReleaseComObject していないというのが、その発言理由の一つです。
(他にも、ページ遷移中に ListBox 操作された場合の対処漏れなどの「手抜き」があります)
とはいえ、無理に ReleaseComObject せずとも、「いずれは」ファイナライザにて
後始末が行われるわけですから、回収タイミングがシビアではないケースにおいては、
明示的に回収せず、ガベージコレクタに任せておくだけでも十分と言えます。
しかし、確保していたオブジェクトが占有性の高い資源であった場合は別です。
「いずれ」ではなく「使わなくなったら即時に」解放しないと、それらを他のプログラムが
利用できなくなってしまいますので、その場合はマネージかアンマネージかを問わず、
他で使われていないことが保証できた時点で、すぐに後始末しておいた方が良いでしょう。
また、解放順序が意味を持つようなオブジェクトの場合も、明示的に後処理すべきです。
具体例を挙げるなら、COM のアウトプロセスサーバー(Excel 等)へのアクセス時や、
短時間の間に連続して幾度も繰り返されし確保されるアンマネージリソースなどでしょうか。
あるいはデータベースやファイル操作、COMポート操作時なども、即時解放が望ましいでしょうね。
投稿者 Tony-G  (中学生)
投稿日時
2012/3/22 20:25:25
魔界の仮面弁士さん、いつもありがとうございます。
教えて頂いた方法で解決しました。ありがとうございました。
ところで、今回は、HtmlElementのDomElementのメソッドを使いましたが、過去に質問した、WebBrowser上のテキストを選択状態にした時の選択範囲のHTMLを調べる方法で、別の掲示板での仮面弁士さんが回答した内容に、DomDocumentというものがありました。
http://hpcgi1.nifty.com/MADIA/VBBBS2/wwwlng.cgi?print+200610/06100044.txt
このDomDocumentとDomElementは、例えば、HtmlElementとHtmlDocumentの関係と同じようなものなのでしょうか。それとも別物?
あと、niftyの掲示板では、変数を使い終わったらReleaseComObjectということをしているようですが
教えて頂いた方法で解決しました。ありがとうございました。
ところで、今回は、HtmlElementのDomElementのメソッドを使いましたが、過去に質問した、WebBrowser上のテキストを選択状態にした時の選択範囲のHTMLを調べる方法で、別の掲示板での仮面弁士さんが回答した内容に、DomDocumentというものがありました。
http://hpcgi1.nifty.com/MADIA/VBBBS2/wwwlng.cgi?print+200610/06100044.txt
このDomDocumentとDomElementは、例えば、HtmlElementとHtmlDocumentの関係と同じようなものなのでしょうか。それとも別物?
あと、niftyの掲示板では、変数を使い終わったらReleaseComObjectということをしているようですが
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2012/3/22 01:12:22
> DeleteAttributeというか、RemoveAttributeというか、そういった類のメソッドがあるといいのですが、どうでしょう。
ありますよ。
http://msdn.microsoft.com/en-us/library/aa752328.aspx
ありますよ。
http://msdn.microsoft.com/en-us/library/aa752328.aspx
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebBrowser1.Navigate("http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=10774")
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim anchor = WebBrowser1.Document.GetElementById("linkNoTag")
TextBox1.Text = anchor.OuterHtml
anchor.DomElement.removeAttribute("id", 0)
TextBox2.Text = anchor.OuterHtml
End Sub
End Class
投稿者 Tony-G  (中学生)
投稿日時
2012/3/21 20:51:42
またまたお世話になります。引き続き、VB2008+XPでのプログラムで質問です。
WebBrowser上の<a>タグを識別するために、<a>タグのHtmlElementのIdプロパティを使ってIdを設定しています。
ただ、WebBrowser上のHTMLをファイルに保存するとき、各<a>タグにセットしたId属性を削除してから保存したいのですが、どうすればいいでしょうか?
HtmlElement.Id = ""とすれば消えるかなとも思ったのですが、保存したHTMLファイルには、<a id="" ...>のように、Id属性が残ったままになっています。
あと、例えば、<a title="xxx" ...>のようなtitle属性を削除したいのですが、HtmlElementには属性削除用のメソッドはないのでしょうか?
SetAttributeやGetAttributeといったメソッドはありますが、DeleteAttributeというか、RemoveAttributeというか、そういった類のメソッドがあるといいのですが、どうでしょう。
HTMLの内容を、該当する属性の部分を正規表現のようなもので検索し、削除することも考えましたが、正規表現は僕にはちょっと難しいので、もっと簡単にできる方法があれば教えてください。
WebBrowser上の<a>タグを識別するために、<a>タグのHtmlElementのIdプロパティを使ってIdを設定しています。
ただ、WebBrowser上のHTMLをファイルに保存するとき、各<a>タグにセットしたId属性を削除してから保存したいのですが、どうすればいいでしょうか?
HtmlElement.Id = ""とすれば消えるかなとも思ったのですが、保存したHTMLファイルには、<a id="" ...>のように、Id属性が残ったままになっています。
あと、例えば、<a title="xxx" ...>のようなtitle属性を削除したいのですが、HtmlElementには属性削除用のメソッドはないのでしょうか?
SetAttributeやGetAttributeといったメソッドはありますが、DeleteAttributeというか、RemoveAttributeというか、そういった類のメソッドがあるといいのですが、どうでしょう。
HTMLの内容を、該当する属性の部分を正規表現のようなもので検索し、削除することも考えましたが、正規表現は僕にはちょっと難しいので、もっと簡単にできる方法があれば教えてください。
魔界の仮面弁士さんの書かれた内容を自分なりに調べ、精進料理しようと思います。