質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

5回答

12920閲覧

【C#】XMLの空タグ、空属性を削除したい。

Lazialize

総合スコア58

XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2018/02/26 02:10

編集2018/02/26 03:03

前提・実現したいこと

こんちには。
現在、C#にてXMLファイルを出力するアプリケーションを作っています。
XML自体の出力はできるのですが、空の要素や属性が多数あり見た目が非常に悪いです。
そのため、空の要素や属性をすべて削除する機能を実装させたいのですが、
私の知識では冗長性のあるコードしか書けなかったため、
どうすればスマートな実装ができるか、皆さんの意見をお聞きしたく質問させていただきました。

このようなXmlを

Xml

1<root> 2 <Name>hogehoge</Name> 3 <Desc>hoge is hoge</Desc> 4 <Category></Category> 5 <Test/> 6 <Features> 7 <Feature From=""> 8 ... 9 </Feature> 10 </Features> 11</root>

このように出力したいです。

Xml

1<root> 2 <Name>hogehoge</Name> 3 <Desc>hoge is hoge</Desc> 4 <Features> 5 <Feature> 6 ... 7 </Feature> 8 </Features> 9</root>

できればコードだけで行いたいのですが
「コードだけでは難しい、こういう方法ならもっと楽」
という方法があれば教えていただけると幸いです。

よろしくお願いします。

補足情報(FW/ツールのバージョンなど)

開発環境:
Visual Studio 2017
C# WPF アプリケーション
.NET FW 4.7

追記

このXmlファイルは、私ではない人が編集することも考えられるものなので見た目の悪いものはできるだけ作りたくありません。

Xmlを構成するタグは独自タグなので、<br/><img>のalt属性など、消すと問題があるかもしれないものは含まれていないと思っていただいて構いません。

また、このXmlファイルは別のアプリケーション(自作のものではない)で読み込むためのXmlです。
そのため、使わない属性等があると誤作動を起こす可能性があります。
なので、できるだけ使わない属性を排除したいというのが考えです。

この考え方そのものが間違っている可能性もありますが……。
Xmlについては殆ど知らないといっても過言ではないので、まずそもそもが間違っているという場合は指摘してください。

情報の不足、大変申し訳ありませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gazette2

2018/02/26 03:05

XmlSerializerですか。
Lazialize

2018/02/26 03:29

アプリケーションで読み込んだ際にXML宣言がエラーを吐く原因になるみたいなので、XmlSerializerではなくXDcumentで行うことを考えています。
Lazialize

2018/02/26 03:29

XmlSerializerのxml宣言を消せる場合は、方法を教えていただけると嬉しいです・・・。
guest

回答5

0

ベストアンサー

XmlSerializerだと仮定して書きます。

例えば次のコードは空の要素を作ります。

[XmlElement] public string Test { get; set; } = "";

この場合、[property name]Specifiedというbool形変数を作って出力をコントロールすることができます。

[XmlIgnore] public bool TestSpecified = false;  // Testという変数を無視してほしい。

[XmlIgnore]はTestSpecifiedという変数自体はXML要素ではないって言うことです。

「追加」
xml宣言文の消し方

XmlSerializer ser = new XmlSerializer(typeof(Group)); var settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }; // A FileStream is used to write the file. using (var fs = new FileStream("test.xml", FileMode.Create)) using (var writer = XmlWriter.Create(fs, settings)) ser.Serialize(writer, myGroup);

投稿2018/02/26 03:16

編集2018/02/26 03:43
gazette2

総合スコア179

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lazialize

2018/02/26 03:40

加筆修正依頼の方へのお返事が遅れましたこと大変申し訳ありませんでした。 加筆修正依頼の方へも書いたとおり、XmlSerializerの使用は考えておりません。 XmlSerializerで出力した場合のXML宣言が消す方法がある場合は、助言をいただけると幸いです。
gazette2

2018/02/26 03:44

XmlWriterSettingsを使用して消すことができます。
Lazialize

2018/02/26 03:52

お早いお返事ありがとうございます。 XmlSerializerで対応できそうです。 お忙しいところ、ご丁寧にお答えいただき、ありがとうございます。
guest

0

データ交換には普通はスキーマが必要です。
XMLのスキーマとしては、今は XML Schema が一般的です。
簡単なXML Schemaから始めよう

もう少し鷹揚にデータ交換したい場合は、JSONを使いましょう。

投稿2018/02/26 03:14

hihijiji

総合スコア4150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lazialize

2018/02/26 03:35

やはりスキーマが一般的なのですね。 すこし、スキーマについて勉強したいと思います。
hihijiji

2018/02/26 03:55

スキーマはデータ構造の事で一般名詞です。 「XML Schema」は W3Cが標準化した固有名詞です。 混同なきようお願いします。
Lazialize

2018/02/26 03:55

今回はgazette2さんの方法が一番簡単にできそうでしたので、gazette2さんをベストアンサーに選ばせていただきました。 この度はありがとうございました。
guest

0

そのため、空の要素や属性をすべて削除する機能を実装させたいのですが、

そもそも論ですが、本当に削除してしまって大丈夫なのでしょうか。

たとえば、HTMLの<br />は属性も中身も指定しない空要素ですが意味を持ちますし、<img>alt=''は「画像は飾りなので省略して問題ない」、一方altなしでは「画像がコンテンツの最重要ポイントで、文字表現ができない」と正反対の意味となります(MDN)。

「見た目が非常に悪い」ものでも、「意味を破壊してしまったもの」よりはずっとマシですし、通常の用法では「XML文の見た目」を気にすることもないかと思います。

投稿2018/02/26 02:28

編集2018/02/26 02:29
maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lazialize

2018/02/26 02:53

<br />は絶対に入っていないと言えるので問題ありません。 タグもすべて独自のタグでして、「無いと困る」という属性はないので大丈夫です。 XMLは私ではない第三者が編集する可能性もあり、見た目の悪いものはできるだけ作りたくありません。 書き忘れてしまったのですが、このXMLファイルは別のアプリケーション(自作のものではありません)で読み込むものでして、無駄な属性などがあると逆にそれが原因で誤作動、あるいはエラーを吐く可能性があるため、できるだけ使わない属性はなくしたいのです。 情報の不足、大変申し訳ありませんでした。 追記しておきます。
guest

0

空要素と言っても、例えば要素の中に空要素があり、それを削除することで新たに空要素が生まれることがあります。
これに対応するには深さ優先探索を行って再帰的に削除していくのが一番簡単ではないでしょうか。

C#

1void RemoveEmpty(XElement element) 2{ 3 foreach (var a in element.Attributes().ToArray()) 4 { 5 if (string.IsNullOrEmpty(a.Value)) 6 { 7 a.Remove(); 8 } 9 } 10 foreach (var e in element.Elements().ToArray()) 11 { 12 RemoveEmpty(e); 13 } 14 if (string.IsNullOrEmpty(element.Value) && !element.HasAttributes) 15 { 16 element.Remove(); 17 } 18} 19 20string source = @"<root> 21 <Name>hogehoge</Name> 22 <Desc>hoge is hoge</Desc> 23 <Category></Category> 24 <Test/> 25 <Features> 26 <Feature From="""">Foo</Feature> 27 </Features> 28</root>"; 29var xml = XElement.Parse(source); 30RemoveEmpty(xml); 31string seperator = "--------------"; 32Console.WriteLine(source); 33Console.WriteLine(seperator); 34Console.WriteLine(xml.ToString());

出力

<root> <Name>hogehoge</Name> <Desc>hoge is hoge</Desc> <Category></Category> <Test/> <Features> <Feature From="">Foo</Feature> </Features> </root> -------------- <root> <Name>hogehoge</Name> <Desc>hoge is hoge</Desc> <Features> <Feature>Foo</Feature> </Features> </root>

投稿2018/02/26 03:54

編集2018/02/26 06:10
Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lazialize

2018/02/26 04:03

すいません。 どうやら、入れ違いになったようです。 今確認しました。 わざわざ出力結果まで出していただき、ありがとうございます。 XDocumentではこのように削除できるのですね。勉強になりました。 今回は既に解決済みにしてしまったので、ベストアンサーにはできませんが、 大変ためになる知識です。 ありがとうございました。
guest

0

こんな感じでしょうか(入力がファイルとなっていますが、そこは適宜……)。

C#

1using System; 2using System.Text; 3using System.Xml; 4using System.Xml.Xsl; 5namespace ConsoleApp1 6{ 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 var xslt = new XslCompiledTransform(); 12 xslt.Load(@"../../XSLTFile1.xslt"); 13 14 var output = new StringBuilder(); 15 var settings = new XmlWriterSettings(); 16 settings.Indent = true; 17 settings.OmitXmlDeclaration = false; 18 19 using (var writer = XmlWriter.Create(output, settings)) 20 { 21 xslt.Transform(@"../../XMLFile1.xml", writer); 22 } 23 24 Console.WriteLine(output.ToString()); 25 } 26 } 27}

XSLTFile1.xslt

<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" > <xsl:output method="xml" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="@* | node()"> <xsl:if test=".!=''"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:if> </xsl:template> </xsl:stylesheet>

投稿2018/02/26 03:18

HARQ

総合スコア181

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lazialize

2018/02/26 03:55

回答ありがとうございました。 わざわざコードまで書いていただき恐縮です。 今回はgazette2さんの方法が一番簡単にできそうでしたので、gazette2さんをベストアンサーに選ばせていただきました。 この度はありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問