2013-02-19 12 views
5

xmlファイルから特定のノードを削除することに関連する質問があります。ここで子ノードのない親ノードを削除

は、XMLの私のサンプルです:

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <nodeA attribute="1"> 
    <nodeB attribute="table"> 
     <nodeC attribute="500"></nodeC> 
     <nodeC attribute="5"></nodeC> 
    </nodeB> 
    <nodeB attribute="3"> 
     <nodeC attribute="4"></nodeC> 
     <nodeC attribute="5"></nodeC> 
     <nodeC attribute="5"></nodeC> 
    </nodeB> 
    <nodeB attribute="placeHolder"> 
    <nodeB attribute="toRemove"> 
     <nodeB attribute="glass"></nodeB> 
     <nodeE attribute="7"></nodeE> 
     <nodeB attribute="glass"></nodeB> 
     <nodeB attribute="glass"></nodeB> 
    </nodeB> 
    </nodeB> 
    <nodeB attribute="3"> 
     <nodeC attribute="4"></nodeC> 
     <nodeC attribute="5"></nodeC> 
     <nodeC attribtue="5"></nodeC> 
    </nodeB> 
    <nodeB attribute="placeHolder"> 
    <nodeB attribute="toRemove"> 
     <nodeB attribute="glass"></nodeB> 
     <nodeE attribute="7"></nodeE> 
     <nodeB attribute="glass"></nodeB> 
     <nodeB attribute="glass"></nodeB> 
    </nodeB> 
    </nodeB> 
    </nodeA> 
</root> 

私は、このノードの子供を削除せずにノードnodeB="toRemove"を削除したいと思います。その後、私はnodeB attribute="placeHolder"と同じことをする必要があります。結果の一部は、そのようになります。

 <nodeB attribute="3"> 
     <nodeC attribute="4"></nodeC> 
     <nodeC attribute="5"></nodeC> 
     <nodeC attribtue="5"></nodeC> 
    </nodeB> 
    <nodeB attribute="glass"></nodeB> 
     <nodeE attribute="7"></nodeE> 
    <nodeB attribute="glass"></nodeB> 
    <nodeB attribute="glass"></nodeB> 

私はそれをachiveするために、このようなコードをしようとしている:

 XmlNodeList nodeList = doc.SelectNodes("//nodeB[@attribute=\"toRemove\"]"); 

     foreach (XmlNode node in nodeList) 
     { 
      foreach (XmlNode child in node.ChildNodes) 
      { 
       node.ParentNode.AppendChild(child); 
      } 
      node.ParentNode.RemoveChild(node); 
     } 
     doc.Save(XmlFilePathSource); 

私は必要な属性toRemoveまたはプレースホルダを持つノードを見つけることができています、しかし、私はないですこのノードの子を1レベル上に移動することができます。この場合、私を助けてくれますか?それはLinq、XDocument、XmlReaderで解決できますが、私はXmlDocumentで作業することを好む。 事前にご連絡いただきありがとうございました。

編集:私はチャックサベージがベローズを書いた(順序を維持するために)わずかに修正されたコードを使用している。この場合

。一度

<nodeB attribute="toRemove"> </nodeB> 

を除去した後、ここ

<nodeB attribute="placeHolder"></nodeB> 

と同じことを行うために@MiMoによって提供わずかに修正されたコード

XElement root = XElement.Load(XmlFilePathSource); 
    var removes = root.XPathSelectElements("//nodeB[@attribute=\"toRemove\"]"); 
    foreach (XElement node in removes.ToArray()) 
    { 
    node.Parent.AddAfterSelf(node.Elements()); 
    node.Remove(); 
    } 
    root.Save(XmlFilePathSource); 

XSLTアプローチは、この場合も同様に非常に有用です。

+0

あなたの 'nodeC'要素の多くに、終了タグがありません。正当な整形式のXMLで質問を更新できますか? –

+0

私は単純化されたXMLファイルを更新しました。ヒントをありがとう、それは他の人のために今読むのが簡単です。答えのために – wariacik

答えて

3

XElement root = XElement.Load(XmlFilePathSource); // or .Parse(string) 
var removes = root.XPathSelectElements("//nodeB[@attribute=\"toRemove\"]"); 
foreach (XElement node in removes.ToArray()) 
{ 
    node.AddBeforeSelf(node.Elements()); 
    node.Remove(); 
} 
root.Save(XmlFilePathSource); 

:XPathは System.Xml.XPath

注2で提供されています:あなたがに変換することができます/ from XmlDocument these extensions XmlDocumentが好きなので使用します。

+0

ここで欠点の1つは、保存された子ノードが、文書の部分に残されずに収容ノードの最後に追加されることです。依頼者は、彼らの所在地を維持することが必須条件だとは言わなかったが、それは容易に可能性がある。 – JLRishe

+0

@JLRishe OPコードを見ると、彼は基本的に同じことをしていますが、私はあなたのことが好きです。 –

+0

私はこのアプローチが本当に好きですが、このケースでは子ノードの場所を保持することを再確認しています。どこにどこで子ノードを文書の一部に保持する方法はありますか? – wariacik

4

問題は、子ノードの列挙中に文書ノードを変更できないことです。既存のノードを変更しようとする代わりに新しいノードを作成してください。これはXmlDocumentを使用するとややこしくなります。このXSLT適用

変換のこの種は、XSLTを使用している最も簡単な方法は、すなわち:入力に

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="nodeB[@attribute='toRemove' or @attribute='placeHolder']"> 
    <xsl:apply-templates/> 
    </xsl:template> 

    <xsl:template match="text()"> 
    </xsl:template> 

    <xsl:template match="@* | *"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

は、出力をファイルです。

<root> 
    <nodeA attribute="1"> 
    <nodeB attribute="table"> 
     <nodeC attribute="500" /> 
     <nodeC attribute="5" /> 
    </nodeB> 
    <nodeB attribute="3"> 
     <nodeC attribute="4" /> 
     <nodeC attribute="5" /> 
     <nodeC attribute="5" /> 
    </nodeB> 
    <nodeB attribute="glass" /> 
    <nodeE attribute="7" /> 
    <nodeB attribute="glass" /> 
    <nodeB attribute="glass" /> 
    <nodeB attribute="3"> 
     <nodeC attribute="4" /> 
     <nodeC attribute="5" /> 
     <nodeC attribtue="5" /> 
    </nodeB> 
    <nodeB attribute="glass" /> 
    <nodeE attribute="7" /> 
    <nodeB attribute="glass" /> 
    <nodeB attribute="glass" /> 
    </nodeA> 
</root> 

XSLTを適用するためのコード単純に:

XslCompiledTransform transform = new XslCompiledTransform(); 
    transform.Load(@"c:\temp\nodes.xslt"); 
    transform.Transform(@"c:\temp\nodes.xml", @"c:\temp\nodes-cleaned.xml"); 

Xに外部ファイルを使用することはできませんSLTは、文字列から読み取ることができますからXMLへのLINQ-とあなたのXPathを使用して

string xsltString = 
    @"<xsl:stylesheet 
     version='1.0' 
     xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> 

     <xsl:output method=""xml"" indent=""yes""/> 

     <xsl:template match=""nodeB[@attribute='toRemove' or @attribute='placeHolder']""> 
     <xsl:apply-templates/> 
     </xsl:template> 

     <xsl:template match=""text()""> 
     </xsl:template> 

     <xsl:template match=""@* | *""> 
     <xsl:copy> 
      <xsl:apply-templates select=""@* | node()""/> 
     </xsl:copy> 
     </xsl:template> 

    </xsl:stylesheet>"; 
    XslCompiledTransform transform = new XslCompiledTransform(); 
    using (StringReader stringReader = new StringReader(xsltString)) 
    using (XmlReader reader = XmlReader.Create(stringReader)) { 
    transform.Load(reader); 
    } 
    transform.Transform(@"c:\temp\nodes.xml", @"c:\temp\nodes-cleaned.xml");  
+0

ありがとう。私はこの種のアプローチを別の時間に使用して、追加のファイルを読み込むことができます。しかし、この特定のケースでは、私は外部ファイルを使用することはできません。私の場合、xsltファイルの読み込みはオプションではありません。 – wariacik

+0

@wariacik:外部ファイルを使わなくてもXSLTを使用することができます。私は答えを広げました。 XSLTの問題は、すでに使い慣れていない人には使いにくいことです。しかし、多くのXML処理を行うと、それらを学習することは良い投資です。 – MiMo

+0

ありがとうございます。私は文字列としてxsltをロードできるかどうかはわかりませんでした。これは私のプロジェクトで非常に役立ちます。 – wariacik

3

私はその古い質問を知っていますが、私はこれをXmlDocumentを使って直接書いています。誰かがそれをこのように行うことを好む場合は、それを追加

XmlNode child_to_remove = parent.ChildNodes[i]; // get the child to remove 

// move all the children of "child_to_remove" to be the child of their grandfather (== parent) 
while(child_to_remove.HasChildNodes) 
    parent.InsertBefore(child_to_remove.ChildNodes[0], child_to_remove); 

parent.RemoveChild(child_to_remove); 

:-)それです、それは誰も助けていただければ幸いです。

関連する問題