C#

XmlDocumentで名前空間と接頭辞を追加する

答えにたどりつくまでに苦労したので、メモしておこう。以下、ATOMに名前空間「urn:photo.hesperus.net」と接頭辞「phn」を追加する例。

XmlDocument atomDocument = new XmlDocument();
XmlElement atomEntry = atomDocument.CreateElement("entry", "http://www.w3.org/2005/Atom");
atomDocument.AppendChild(atomEntry);

// ここがポイント。<entry>要素に名前空間と接頭辞を追加する。
XmlAttribute xmlnsPhn = atomDocument.CreateAttribute("xmlns", "phn", "http://www.w3.org/2000/xmlns/");
xmlnsPhn.Value = "urn:photo.hesperus.net";
atomEntry.Attributes.Append(xmlnsPhn);

XmlElement phnProperty = atomDocument.CreateElement("phn", "property", "urn:photo.hesperus.net");
atomEntry.AppendChild(phnProperty);

XmlAttribute propertyName = atomDocument.CreateAttribute("name");
propertyName.Value = "thumbnail";
phnProperty.Attributes.Append(propertyName);

XmlAttribute propertyHref = atomDocument.CreateAttribute("href");
propertyHref.Value = "/img/hoge.jpg";
phnProperty.Attributes.Append(propertyHref);

出力は次のようになる。

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:phn="urn:photo.hesperus.net">
  <phn:property name="thumbnail" href="/img/hoge.jpg" />
</entry>

まるで「xmlns」が名前空間「http://www.w3.org/2000/xmlns/」の接頭辞であるかのようだ。この名前空間を知らないと、うまくいかない。参考にしたのは英語のページ。何が書かれているのか、さっぱりわからなかったが、コーディングは理解した。

http://stackoverflow.com/questions/10807173/xmldocument-prefix-not-being-outputted

失敗例:その1

<entry>要素に名前空間「urn:photo.hesperus.net」と接頭辞「phn」を追加しないと、<phn:property>要素に追加されてしまう。

<entry xmlns="http://www.w3.org/2005/Atom">
  <phn:property xmlns:phn="urn:photo.hesperus.net" name="thumbnail" href="/img/hoge.jpg" />
</entry>

<phn:property>要素がひとつだけなら、そもそも接頭辞を使うまでもない。

<entry xmlns="http://www.w3.org/2005/Atom">
  <property xmlns="urn:photo.hesperus.net" name="thumbnail" href="/img/hoge.jpg" />
</entry>

だが、<phn:property>要素が複数あったり、接頭辞「phn」を使う他の要素があったりすると、合理性を欠くことになる。

<entry xmlns="http://www.w3.org/2005/Atom">
  <phn:property xmlns:phn="urn:photo.hesperus.net" name="thumbnail" href="/img/hoge.jpg" />
  <phn:property xmlns:phn="urn:photo.hesperus.net" name="date" value="2016-04-13" />
  <phn:property xmlns:phn="urn:photo.hesperus.net" name="place" value="tokyo" />
  <phn:info xmlns:phn="urn:photo.hesperus.net">thanks: everyone</phn:info>
</entry>

これは避けたい。接頭辞を使わなくても、ちょっと納得いかない感じだ。

<entry xmlns="http://www.w3.org/2005/Atom">
  <property xmlns="urn:photo.hesperus.net" name="thumbnail" href="/img/hoge.jpg" />
  <property xmlns="urn:photo.hesperus.net" name="date" value="2016-04-13" />
  <property xmlns="urn:photo.hesperus.net" name="place" value="tokyo" />
  <info xmlns="urn:photo.hesperus.net">thanks: everyone</info>
</entry>

失敗例:その2

形から察すると「xmlns」は接頭辞、「phn」はローカル名、「urn:photo.hesperus.net」は値に見えるので、何となくそんな感じでやってみた。

XmlElement xmlnsPhn = atomDocument.CreateAttribute("xmlns", "phn", "urn:photo.hesperus.net");
atomEntry.Attributes.Append(xmlnsPhn);

CreateAttribute()のところでエラー。名前空間がどうこうとか意味不明のことを言われる。よく見れば、やってることも意味不明だったが、結果的には正解に近かったな。

失敗例:その3

<entry>要素にダミーの属性を追加するとマシになるが、出力されたものを見れば、やはりダミーの属性は無駄だと思う。接頭辞の定義だけで良い。

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:phn="urn:photo.hesperus.net" phn:dummyAttribute="dummyValue">
  <phn:property name="thumbnail" href="/img/hoge.jpg" />
</entry>

追記

混乱をきたさないように追記しておくと、ATOMのルート要素は<feed>と<entry>のどちらでも良い。RSSで使われるのは、ルート要素が<feed>のATOM。ルート要素が<entry>のATOMは、あまり見られない。

(2016/04/14 初稿)