【问题标题】:Add XML node without overwriting existing ones添加 XML 节点而不覆盖现有节点
【发布时间】:2014-05-06 16:23:37
【问题描述】:

我目前正在使用 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>

Item 节点包含所有读取到的 Kinect 语音识别器识别的信息。目标是:每识别一个新词,就会添加一个新的&lt;Item&gt; 节点及其对应的属性。

我在更新过程中遇到问题,即每次我添加一个新节点时,它都会覆盖最后一个节点,最后只有&lt;Item&gt; 节点。我四处搜索并尝试从其搜索结果中应用解决方案,但没有成功。

写入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());
        }
    }

任何帮助将不胜感激!

为了更方便测试,我将代码添加到一个更简单的App中只是为了测试这个方法:

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>

【问题讨论】:

  • 您的代码对我来说工作正常,并为每次调用WriteXml 在文件末尾添加一个新行。您在哪里以及如何调用该方法?这种方法是唯一一种写入 XML 目标文件的方法吗?
  • 我在名为 spRecEng_SpeechRecognized() 的方法上调用该方法,每当语音识别应用程序识别给定语音时,都会调用该方法。我想我也会尝试一下,并在一个非常简单的应用程序中测试这个 WriteXML() 方法(我现在将其添加到原始帖子中),但它仍然没有工作......
  • 示例应用程序按预期工作!我在生成的 XML 中有两行。

标签: xml add


【解决方案1】:

如果必须使用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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-19
    • 1970-01-01
    • 2020-10-28
    • 2018-05-31
    • 1970-01-01
    相关资源
    最近更新 更多