添加XML节点而不覆盖现有节点

时间:2014-05-06 16:23:38

标签: xml add

我目前正在使用Microsoft Kinect SDK开发语音识别应用程序,输出应该是遵循特定结构的XML文件,例如:

<?xml version="1.0" encoding="UTF-8"?>
<Speech>
   <Item Words="hello" Confidence="0,5705749" Semantic="Child" />
   <Item Words="goodbye" Confidence="0,7705913" Semantic="Child" />
</Speech>

项目节点包含识别Kinect语音识别器的所有读取信息。目标是:每次识别新单词时,都会添加一个新的<Item>节点及其相应的属性。

我遇到了更新过程的问题,即每次添加新节点时,它都会覆盖最后一个仅以<Item>节点结束的节点。我已经搜索过并尝试从搜索结果中应用解决方案,但没有成功。

写入XML文件的函数如下:

 void WriteXML(string result, float confidence, string semantic, string typeOfSpeech)
 {
        try
        {
            //pick whatever filename with .xml extension
            string filename = "XML" + "SpeechOutput" + ".xml";

            XmlDocument xmlDoc = new XmlDocument();

            try
            {
                xmlDoc.Load(filename);
            }
            catch (System.IO.FileNotFoundException)
            {
                //if file is not found, create a new xml file
                XmlTextWriter xmlWriter = new XmlTextWriter(filename, System.Text.Encoding.UTF8);
                xmlWriter.Formatting = Formatting.Indented;
                xmlWriter.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
                xmlWriter.WriteStartElement("Speech");
                xmlWriter.Close();
                xmlDoc.Load(filename);
            }

            XmlNode root = xmlDoc.DocumentElement;
            XmlNode lastWord = root.LastChild;

            XmlElement childNode = xmlDoc.CreateElement("Item");
            childNode.SetAttribute("Words", result);
            childNode.SetAttribute("Confidence", confidence.ToString());
            childNode.SetAttribute("Semantic", semantic);

            root.InsertAfter(childNode, lastWord);

            xmlDoc.Save("W:\\" + filename);
        }
        catch (Exception ex)
        {
            WriteError(ex.ToString());
        }
    }

非常感谢任何帮助!

为了便于测试,我将代码添加到更简单的应用程序中以测试此方法:

namespace XMLTesting
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private string typeOfSpeech;

    public MainWindow()
    {
        InitializeComponent();
        WriteXML("test", 1, "semantic", "typeofspeech");
        WriteXML("test2", 2, "semantic", "typeofspeech");
    }

    void WriteXML(string result, float confidence, string semantic, string typeOfSpeech)
    {
        try
        {
            //pick whatever filename with .xml extension
            string filename = "XML" + "SpeechOutput" + ".xml";

            XmlDocument xmlDoc = new XmlDocument();

            try
            {
                xmlDoc.Load(filename);
            }
            catch (System.IO.FileNotFoundException)
            {
                //if file is not found, create a new xml file
                XmlTextWriter xmlWriter = new XmlTextWriter(filename, System.Text.Encoding.UTF8);
                xmlWriter.Formatting = Formatting.Indented;
                xmlWriter.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
                xmlWriter.WriteStartElement("Speech");
                xmlWriter.Close();
                xmlDoc.Load(filename);
            }

            XmlNode root = xmlDoc.DocumentElement;
            XmlNode lastWord = root.LastChild;

            XmlElement childNode = xmlDoc.CreateElement("Item");
            childNode.SetAttribute("Words", result);
            childNode.SetAttribute("Confidence", confidence.ToString());
            childNode.SetAttribute("Semantic", semantic);

            root.InsertAfter(childNode, lastWord);

            xmlDoc.Save("W:\\" + filename);

        }
        catch (Exception ex)
        {
            WriteError(ex.ToString());
        }
    }

    void WriteError(string str)
    {
        //outputBox.Text = str;
    }
}

}

此应用程序的输出文件是:

<?xml version="1.0" encoding="UTF-8"?>
 <Speech>
 <Item Words="test2" Confidence="2" Semantic="semantic" />
</Speech>

而不是:

<?xml version="1.0" encoding="UTF-8"?>
  <Speech>
    <Item Words="test" Confidence="1" Semantic="semantic" />
    <Item Words="test2" Confidence="2" Semantic="semantic" />
  </Speech>

1 个答案:

答案 0 :(得分:0)

如果使用XmlDocument类是必要的,那么我可以建议一些增强功能:

  • 不要使用例外来检查文件是否存在。使用File.Exists
  • 如果文件不存在,请创建它。然后,加载操作应始终有效(如果文件已成功创建),并且您只需要一次加载操作
  • 仅定义完整文件名(名称+位置)一次并在任何地方使用它。这应该可以减少尝试访问(读取或写入)文件时的错误。

略微修改后的WriteXml(适用于我):

void WriteXML(string result, float confidence, string semantic, string typeOfSpeech)
{
    try
    {
        //pick whatever filename with .xml extension
        string filename = Path.Combine("W:\\", "XMLSpeechOutput.xml");

        //if file is not found, create a new xml file
        if (!File.Exists(filename))
        {           
            XmlTextWriter xmlWriter = new XmlTextWriter(filename, System.Text.Encoding.UTF8);
            xmlWriter.Formatting = Formatting.Indented;
            xmlWriter.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
            xmlWriter.WriteStartElement("Speech");
            xmlWriter.Close();
        }
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(filename);
        XmlNode root = xmlDoc.DocumentElement;
        XmlNode lastWord = root.LastChild;

        XmlElement childNode = xmlDoc.CreateElement("Item");
        childNode.SetAttribute("Words", result);
        childNode.SetAttribute("Confidence", confidence.ToString());
        childNode.SetAttribute("Semantic", semantic);

        root.InsertAfter(childNode, lastWord);

        xmlDoc.Save(filename);
    }
    catch (Exception ex)
    {
        WriteError(ex.ToString());
    }
}

如果您可以使用其他技术来访问/修改XML结构,那么我建议您使用LINQ2XML - 对于当前问题,使用将减少代码行。我的示例包含两个扩展方法:

  • 第一个是创建打开指定的XML文件(如果文件不存在,则创建一个空文件)
  • 第二个在XML文件末尾添加一行

扩展代码:

public static class ProjectExtensions
{
    /// <summary>
    /// Loads the file with the specified name.
    /// If the file does not exist an empty file is created.
    /// </summary>
    /// <param name="xmlFile">File location with name: c:\xml\input.xml</param>
    /// <returns>A filled XDocument object</returns>
    public static XDocument CreateOrLoad(this String xmlFile)
    {
        // if the XML file does not exist
        if (!File.Exists(xmlFile))
        {
            // create an empty file
            var emptyXml = new XElement("Speech");
            // and save it under the specified name (and location)
            emptyXml.Save(xmlFile);         
        }
        // load the file (it was either created or it exists already)
        return XDocument.Load(xmlFile);
    }

    /// <summary>
    /// Adds new row at the end of the specified XML document.
    /// </summary>
    /// <param name="result">TODO</param>
    /// <param name="confidence">TODO</param>
    /// <param name="semantic">TODO</param>
    public static void AppendRow(this XDocument document, string result, float confidence, string semantic, string typeOfSpeech)
    {
        // prepare/construct the row to add
        var row = new XElement("Item",  new XAttribute("Word", result),
                                        new XAttribute("Precision", confidence.ToString()),
                                        new XAttribute("Semantic", semantic));
        // take the root node
        var root = document.Root;
        // the xml is empty
        if (!root.Elements().Any())
        {
            // just add the node
            root.Add(row);
        }
        else
        {
            // add the node after at the end of the file
            root.Elements().Last().AddAfterSelf(row);
        }
    }
}

可以像这样使用:

var filename = "W:\\XMLSpeechOut.xml";
//
var xml = filename.CreateOrLoad();
xml.AppendRow("A", 10.5f, "B", "C");
xml.AppendRow("D", 11.0f, "E", "F");
xml.Save(filename);
// alternative one-liner usage (open or create, append, save)
filename.CreateOrLoad().AppendRow("G", 11.5f, "H", "I").Save(filename);

输出结果为:

<?xml version="1.0" encoding="utf-8"?>
<Speech>
  <Item Word="A" Precision="10,5" Semantic="B" />
  <Item Word="D" Precision="11" Semantic="E" />
  <Item Word="G" Precision="11,5" Semantic="H" />
</Speech>