0

XML ファイルを取得し、入力ファイルの何千もの繰り返しノードから複数の出力 xml ファイルを作成する必要があります。ソースファイル「AnimalBatch.xml」は次のようになります。

<?xml version="1.0" encoding="utf-8" ?>
<Animals>
<Animal id="1001">
<Quantity>One</Quantity>
<Adjective>Red</Adjective>
<Name>Rooster</Name>
</Animal>
<Animal id="1002">
<Quantity>Two</Quantity>
<Adjective>Stubborn</Adjective>
<Name>Donkeys</Name>
</Animal>
<Animal id="1003">
<Quantity>Three</Quantity>
<Color>Blind</Color>
<Name>Mice</Name>
</Animal>
</Animals>

しかし、実際には CR/LF 文字は含まれていません。実際のテキスト ストリームは次のようになります。

<?xml version="1.0" encoding="utf-8" ?><Animals><Animal id="1001"><Quantity>One</Quantity><Adjective>Red</Adjective><Name>Rooster</Name></Animal><Animal id="1002"><Quantity>Two</Quantity><Adjective>Stubborn</Adjective><Name>Donkeys</Name></Animal><Animal id="1003"><Quantity>Three</Quantity><Color>Blind</Color><Name>Mice</Name></Animal></Animals>

プログラムは、繰り返しの「動物」を分割し、次の名前の 3 つのファイルを生成する必要があります: Animal_1001.xml、Animal_1002.xml、および Animal_1003.xml

XmlDocument を使用して、これについて以前に質問がありましたが、既に回答がありました。
参照: [XmlDocument を使用して XML ファイルを複数の xml に分割する][1]

この質問は、XmlReader を使用して要素を取得し、それらから XmlDocument 要素を作成する方法に関するものです。


Animal_1001.xml:
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>One</Quantity>
<Adjective>Red</Adjective>
<Name>Rooster</Name>
</Animal>


Animal_1002.xml
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>Two</Quantity>
<Adjective>Stubborn</Adjective>
<Name>Donkeys</Name>
</Animal>


Animal_1003.xml>
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>Three</Quantity>
<Adjective>Blind</Adjective>
<Name>Mice</Name>
</Animal>

動作するコードは次のとおりです-ただし、入力ファイルに改行がある場合のみ:

    static void SplitXMLReader() 
    {
        string strFileName;
        string strSeq;

        XmlReader doc = XmlReader.Create("C:\\AnimalBatch.xml");

        while (doc.Read())
        {
            if (doc.Name=="Animal")
            {
                strSeq = doc.GetAttribute("id");

                XmlDocument outdoc = new XmlDocument();
                XmlDeclaration xmlDeclaration = outdoc.CreateXmlDeclaration("1.0", "utf-8", null);
                XmlElement rootNode = outdoc.CreateElement(doc.Name);

                rootNode.InnerXml = doc.ReadInnerXml();
                outdoc.InsertBefore(xmlDeclaration, outdoc.DocumentElement);
                outdoc.AppendChild(rootNode);

                strFileName = "Animal_" + strSeq + ".xml";
                outdoc.Save("C:\\" + strFileName);
            }
        }
    }

各要素の後に改行がある「AnimalBatch.xml」のコピーに対してこのプログラムを実行すると、動作し、必要に応じて Animal_xxxx.xml ファイルが作成されます。AnimalBatch.xml がフォーマットされていないテキストのストリームのように見える場合、最初の Animal を取得し、1001 の ID を取得して、出力ファイルを正常に書き込みます。後続の Animal 要素を読み取ることはできますが、「id」属性を取得できず、属性から読み取ろうとしている strSeq 変数が null または空白であるため、「Animal_.xml」という名前の出力ファイルを書き込むことになります。最終的に、2 番目のファイルには次の内容のみが含まれます。

<?xml version="1.0" encoding="utf-8"?>
<Animal />

これにより、XmlReader は、少なくとも doc.Read() メソッド、 (doc.Name=="Animal") ステートメント、またはそれ以降の "strSeq = doc.GetAttribute("id"); " の範囲で、 -<Animal id="1002"> タグの後に CR/LF がある場合、動作が異なります。

私の本当の質問は、doc.GetAttribute("id"); を実行するときだと思います。ドキュメント内のカーソルはどこにありますか? そして、「1001」以降のものを取得できないのはなぜですか - これは機能しますか?

John は、XML は書式設定を気にしないと言いました - 私もいつもそう思っていました - しかし、これは困惑しています。また、私のアプリケーションでは、SSIS を介して SQL から引き出しており、XML オブジェクトではなくテキスト ストリームであるため、XML を取得できる唯一の方法はフォーマットされていません。

4

3 に答える 3

0

outdoc にルート ノードを作成する必要があります。次のコードを使用します。

    static void SplitXMLTextReader()
    {

        string strFileName;
        string strSeq = "0";

        XmlTextReader doc = new XmlTextReader(("C:\\AnimalBatch.xml"));
        doc.WhitespaceHandling = WhitespaceHandling.None;

        while (doc.Read())
        {
            switch (doc.Name)
            {
                case "Animal":
                    XmlDocument outdoc = new XmlDocument();
                   XmlDeclaration xmlDeclaration = outdoc.CreateXmlDeclaration("1.0", "utf-8", null);
                       XmlElement rootNode = outdoc.CreateElement(doc.Name);
                    rootNode.InnerXml = doc.ReadInnerXml();
                    outdoc.InsertBefore(xmlDeclaration, outdoc.DocumentElement);
                    outdoc.AppendChild(rootNode);


                    doc.MoveToFirstAttribute();
                    if (string.Compare(doc.Name, "id", true) == 0)
                    {
                        strSeq = doc.Value;
                    }
                    strFileName = "Animal_" + strSeq + ".xml";
                    outdoc.Save("C:\\" + strFileName);
                    break;
            }
        }

    }
于 2012-08-27T11:06:35.113 に答える
0
static void SplitXMLReader()
{
    string strFileName;
    string strSeq;

    XmlReader doc = XmlReader.Create("C:\\AnimalBatch.xml");

    while (doc.Read())
    {
        if (doc.Name=="Animal")
        {
            strSeq = doc.GetAttribute("id");

            XmlDocument outdoc = new XmlDocument();
            XmlDeclaration xmlDeclaration = outdoc.CreateXmlDeclaration("1.0", "utf-8", null);
            XmlElement rootNode = outdoc.CreateElement(doc.Name);

            rootNode.InnerXml = doc.ReadInnerXml();
            outdoc.InsertBefore(xmlDeclaration, outdoc.DocumentElement);
            outdoc.AppendChild(rootNode);

            strFileName = "Animal_" + strSeq + ".xml";
            outdoc.Save("C:\\" + strFileName);
        }
    }
}
于 2012-08-27T21:00:40.570 に答える
0

まず第一に、outdocどこにも何も割り当てていません...現在のノード データを入力して保存したかったのでしょうか? また、1 つのXmlDocumentオブジェクトを作成してから、ループ内でそれをクリア/塗りつぶし、ループ内で数千回新しいオブジェクトを作成するのは良い考えではありません...

XmlReaderまた、一度に 1 つの要素を移動していることにも注意してください。したがって、コード atm は次のようになります。

  1. 呼び出しXmlRead()て、どのような場合にも該当しない (最初の?xml宣言を読み上げます)
  2. 一度呼び出しXmlRead()て、ケースに落ちて、id属性に移動して空のファイルを書き込みます。
  3. XmlRead() \ を10 回呼び出し、次のAnimal要素まですべてをスキップします。

<Animal>タグ内からデータを取得する 1 つのソリューションは、 msdn の This example に似ています。

2 つ目は、たとえばReadToFollowingを使用したReadInnerXmlメソッドなど、より便利な方法を考えることです。また、GetAttribute メソッドを見てください。

私の手順は次のとおりです。

  1. string toFile = "";
  2. <Animal>タグまでファイルを読み取ります。
  3. GetAttribute("id");
  4. toFile = ReadInnerXml();
  5. ファイルに書き込みtoFileます ;)
  6. doc.ReadToFollowing("Animal");

コンパイラで書いたものをチェックしていないので、おそらくいくつかの小さな調整を加えて...

于 2012-08-27T07:03:11.070 に答える