6

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>

私はそれを達成するためにこのようなコードを試してきました:

        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またはplaceHolderを持つノードを見つけることはできますが、このノードの子を1レベル上に移動することはできません。この場合、私を助けてくれませんか。Linq、XDocument、XmlReaderを使用することで解決できますが、私はXmlDocumentを使用することを好みます。事前にご協力いただきありがとうございます。

編集:

この場合、Chuck Savageが以下に書いた(順序を維持するために)わずかに変更されたコードを使用しました。一度削除する

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

そして、同じことをします

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

これが少し変更されたコードです

  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);

この場合、@MiMoによって提供されるxsltアプローチも非常に役立ちます。

4

3 に答える 3

5

問題は、子を列挙している間はドキュメントノードを変更できないことです。既存のノードを変更するのではなく、新しいノードを作成する必要があります。これは、を使用すると少し注意が必要になります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");

XSLTに外部ファイルを使用できない(または望ましくない)場合は、文字列から読み取ることができます。

  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");    
于 2013-02-19T23:19:06.767 に答える
4

Linq-to-XMLとXPathを使用して、

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:XmlDocumentを使用するため、これらの拡張機能を使用してXmlDocumentとの間で変換できます。

于 2013-02-19T23:43:53.027 に答える
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);

それだけです:-)、それが誰かを助けることを願っています。

于 2013-06-01T09:27:27.310 に答える