SVGはXMLベースのベクターデータ用フォーマットで業界標準(?)らしい。
自分が必要なのはレーザー加工用の情報が入っている「path」って要素で、円弧などもこちらで定義している。
これの編集と追加をしたかったのだけれど、面倒そうなのでもういっそ文字列操作で済まそうかと思ったが、調べてみたら意外とすっきりXmlパーサで実装できました。変な制限がつかないで済んでえがった。
※A
まず、なんだかよく分かっていないけれど、「http://www.w3.org/2000/svg」文字列をマネージャ経由で渡す必要がある。
そして、XPathというらしいけれど「/a:svg/a:g/a:path」みたいに直接パスを指定してXmlNodeListを取得できる。(「a」は名前空間?)
※B
CloneNode(…)でコピーでき、現在位置に対してInsertBefore(…)やInsertAfter(…)で挿入できる。
現在位置もNodeで普通のリスト要素のように保持できたり。
// ログ出力クラス
private LogUtil logUtil = null;
/// 要素を解析し変換する
public System.Xml.XmlDocument ConvSvg(System.Xml.XmlDocument xmlDoc)
{
// 引数の確認
if (xmlDoc is null) { return null; }
try
{
// -- ※A ->
// 名前空間マネージャの生成
System.Xml.XmlNamespaceManager nsmgr = new System.Xml.XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("a", "http://www.w3.org/2000/svg");
// 「path」の取得
System.Xml.XmlNodeList nodeList = xmlDoc.SelectNodes("/a:svg/a:g/a:path", nsmgr);
// <- ※A --
// 取得の確認
if (nodeList is null || nodeList.Count <= 0)
{
this.logUtil.WriteLog("パス(path) が取得できませんでした。", LogUtil.LogLevel.Error);
this.logUtil.WriteLog(" → オブジェクト は予め パス(path) に変換する必要があります", LogUtil.LogLevel.Info);
this.logUtil.WriteLog(" → /svg/g/path が存在するか確認してください", LogUtil.LogLevel.Info);
return null;
}
// 取得したパスで回る
foreach (System.Xml.XmlNode node in nodeList)
{
// 図形情報(d属性?)の取得
string dValue = null;
try
{
dValue = node.Attributes["d"].Value;
}
catch (Exception)
{
dValue = null;
}
if (string.IsNullOrEmpty(dValue) == true) { continue; }
// 図形情報を確認して図形の種類を取得する
DValueTypes dValueType = this.GetDValueType(dValue);
// style属性(「;」「:」区切り。strokeが線色?)の取得
string sValue = null;
try
{
sValue = node.Attributes["style"].Value;
}
catch (Exception)
{
sValue = null;
}
// style属性を確認して処理の種類を取得する
SValueTypes sValueType = this.GetSValueType(sValue);
// 線色による分岐
if (sValueType == SValueTypes.Delete)
{
// 削除する
node.ParentNode.RemoveChild(node);
continue;
}
// 図形種類による分岐
string[] dValues = null;
if (dValueType == DValueTypes.LineRelative || dValueType == DValueTypes.LineAbsolute)
{
dValues = this.ConvLine(dValue, dValueType, sValueType);
}
else if (dValueType == DValueTypes.ArcRelative || dValueType == DValueTypes.ArcAbsolute)
{
dValues = this.ConvArc(dValue, dValueType, sValueType);
}
else
{
this.logUtil.WriteLog("図形の種類の特定に失敗しました。", LogUtil.LogLevel.Error);
this.logUtil.WriteLog(" → 現バージョンでは「円弧(a)」「移動(m)で定義の直線」のみ対応しています。(「直線(l)で定義の直線」は非対応)", LogUtil.LogLevel.Info);
this.logUtil.WriteLog(" → " + dValue, LogUtil.LogLevel.Info);
continue;
}
// 処理結果の確認
if (dValues is null || dValues.Length <= 0) { continue; }
// -- ※B ->
// 変換結果で回る
System.Xml.XmlNode lastNode = node;
for (int i = 0; i < dValues.Length; i++)
{
if (i == 0)
{
//-- 1件目の場合
// 置き換える
node.Attributes["d"].Value = dValues[i];
continue;
}
//-- 以下、2件目以降の場合
// コピーして置き換える
System.Xml.XmlNode newNode = node.CloneNode(true);
newNode.Attributes["id"].Value += "_" + (i + 1).ToString().PadLeft(3, '0');
newNode.Attributes["d"].Value = dValues[i];
node.ParentNode.InsertBefore(newNode, lastNode);
// 現在の位置を保存する
lastNode = newNode;
}
// <- ※B --
}
}
catch (Exception ex)
{
// ログ出力
this.logUtil.WriteLog(LogUtil.LogLevel.Delimiter);
this.logUtil.WriteLog(ex.ToString(), LogUtil.LogLevel.Fatal);
this.logUtil.WriteLog(LogUtil.LogLevel.Delimiter);
this.logUtil.WriteLog("変換処理で例外が発生しました。", LogUtil.LogLevel.Fatal);
// 戻り値のクリア
xmlDoc = null;
}
// 返す
return xmlDoc;
}
※動作しているコードの該当箇所をそのままコピーしました
0 件のコメント:
コメントを投稿