public void ParseConfig(XmlElement config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            Debug.Assert(!string.IsNullOrEmpty(config.GetAttribute("language")));
            Debug.Assert(!string.IsNullOrEmpty(config.GetAttribute("engine")));
            _primaryLanguage = Localor.StringToLanguage(
                                            config.GetAttribute("language"));
            _engineType = (EngineType)Enum.Parse(typeof(EngineType),
                                            config.GetAttribute("engine"));

            XmlElement eleLangData = config.SelectSingleNode("languageData") as XmlElement;
            VoiceCreationLanguageData languageData = new VoiceCreationLanguageData();
            if (eleLangData != null)
            {
                languageData.ParseLanguageDataFromXmlElement(true, eleLangData);
                languageData.SetLanguageData(_primaryLanguage);
            }
            else
            {
                languageData.CartQuestions = config.SelectSingleNode("question/@path").InnerText;
            }

            _voiceName = config.GetAttribute("voiceName");
            _tokenId = config.GetAttribute("tokenId");

            _fontPath = config.SelectSingleNode("font/@path").InnerText;

            TtsPhoneSet phoneSet = Localor.GetPhoneSet(_primaryLanguage);
            XmlScriptValidateSetting validateSetting = new XmlScriptValidateSetting(phoneSet, null);
            _scriptFile = XmlScriptFile.LoadWithValidation(config.SelectSingleNode("script/@path").InnerText, validateSetting);
            _scriptFile.Remove(ScriptHelper.GetNeedDeleteItemIds(_scriptFile.ErrorSet));

            FileMap = new FileListMap();
            FileMap.Load(config.SelectSingleNode("filemap/@path").InnerText);

            _weightTable = new WeightTable(_primaryLanguage, _engineType);
            _weightTable.Load(config.SelectSingleNode("weighttable/@path").InnerText);

            _cartTreeManager = new CartTreeManager();
            _cartTreeManager.CartTreeDir = config.SelectSingleNode("treedir/@path").InnerText;
            if (!Directory.Exists(_cartTreeManager.CartTreeDir))
            {
                string message = string.Format(CultureInfo.InvariantCulture,
                    "The treeDir path does not exist at [{0}]",
                    _cartTreeManager.CartTreeDir);
                throw new DirectoryNotFoundException(message);
            }

            _cartTreeManager.CartQuestionFile = languageData.CartQuestions;
            if (!File.Exists(_cartTreeManager.CartQuestionFile))
            {
                string message = string.Format(CultureInfo.InvariantCulture,
                    "The tree question file path does not exist at [{0}]",
                    _cartTreeManager.CartQuestionFile);
                throw new DirectoryNotFoundException(message);
            }

            _cartTreeManager.UnitDescriptFile = config.SelectSingleNode("unitdescript/@path").InnerText;
            if (!File.Exists(_cartTreeManager.UnitDescriptFile))
            {
                string message = string.Format(CultureInfo.InvariantCulture,
                    "The unit description file path does not exist at [{0}]",
                    _cartTreeManager.UnitDescriptFile);
                throw new DirectoryNotFoundException(message);
            }

            _unitFeatureFilePath = config.SelectSingleNode("wavesequence/@path").InnerText;
            if (!File.Exists(_unitFeatureFilePath))
            {
                string message = string.Format(CultureInfo.InvariantCulture,
                    "The wave sequence file path does not exist at [{0}]",
                    _unitFeatureFilePath);
                throw new DirectoryNotFoundException(message);
            }

            _wave16kDirectories.Clear();
            foreach (XmlNode dirNode in config.SelectNodes("wave16k/@path"))
            {
                string waveDir = dirNode.InnerText.Trim();
                if (!Directory.Exists(waveDir))
                {
                    string message = string.Format(CultureInfo.InvariantCulture,
                        "The wave16k path does not exist at [{0}]",
                        waveDir);
                    throw new DirectoryNotFoundException(message);
                }

                _wave16kDirectories.Add(waveDir);
            }

            _segmentDirectories.Clear();
            foreach (XmlNode dirNode in config.SelectNodes("segment/@path"))
            {
                string alignmentDir = dirNode.InnerText.Trim();
                if (!Directory.Exists(alignmentDir))
                {
                    string message = string.Format(CultureInfo.InvariantCulture,
                        "The alignment path does not exist at [{0}]",
                        alignmentDir);
                    throw new DirectoryNotFoundException(message);
                }

                _segmentDirectories.Add(alignmentDir);
            }
        }
        /// <summary>
        /// Extracts features from the given script.
        /// </summary>
        /// <param name="script">
        /// The xml script file.
        /// </param>
        /// <param name="fileListMap">
        /// The file list map.
        /// </param>
        /// <param name="alignmentDir">
        /// The alignment directory.
        /// </param>
        /// <param name="waveDir">
        /// The wave directory.
        /// </param>
        /// <returns>
        /// The extracted features in training sentence set.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Exception.
        /// </exception>
        public TrainingSentenceSet Extract(XmlScriptFile script, FileListMap fileListMap, string alignmentDir,
            string waveDir)
        {
            if (script == null)
            {
                throw new ArgumentNullException("script");
            }

            if (fileListMap == null)
            {
                throw new ArgumentNullException("fileListMap");
            }

            if (alignmentDir == null)
            {
                throw new ArgumentNullException("alignmentDir");
            }

            if (waveDir == null)
            {
                throw new ArgumentNullException("waveDir");
            }

            TrainingSentenceSet sentenceSet = new TrainingSentenceSet { FileListMap = fileListMap };
            List<string> errList = new List<string>();

            foreach (string sid in fileListMap.Map.Keys)
            {
                ScriptItem item = script.ItemDic[sid];

                try
                {
                    // Loads the segmentation file.
                    SegmentFile segmentFile = new SegmentFile();
                    segmentFile.Load(fileListMap.BuildPath(alignmentDir, sid, "txt"));

                    // Loads the waveform file to set the end time of the last segmentation.
                    WaveFile waveFile = new WaveFile();
                    waveFile.Load(fileListMap.BuildPath(waveDir, sid, FileExtensions.Waveform));
                    segmentFile.WaveSegments[segmentFile.WaveSegments.Count - 1].EndTime = waveFile.Duration;

                    // Extracts the single script item.
                    Sentence sentence = Extract(item, segmentFile);
                    sentence.TrainingSet = sentenceSet;
                    sentenceSet.Sentences.Add(sid, sentence);
                }
                catch (Exception e)
                {
                    if (!(e is InvalidDataException))
                    {
                        throw;
                    }

                    // Removes the error sentences.
                    Logger.Log(Helper.BuildExceptionMessage(e));
                    script.Remove(sid);
                    errList.Add(sid);
                }
            }

            fileListMap.RemoveItems(errList);
            return sentenceSet;
        }
        /// <summary>
        /// Merge scripts in a folder into a script file.
        /// Error items are removed from the output file.
        /// </summary>
        /// <param name="scriptDir">Dir conataining script file.</param>
        /// <param name="errorSet">Error set.</param>
        /// <param name="resetId">True means resetting id.</param>
        /// <param name="validateSetting">Validation setting.</param>
        /// <param name="contentController">Contenct controller.</param>
        /// <returns>Xml script file.</returns>
        public static XmlScriptFile MergeScripts(string scriptDir, ErrorSet errorSet,
            bool resetId, XmlScriptValidateSetting validateSetting, object contentController)
        {
            if (string.IsNullOrEmpty(scriptDir))
            {
                throw new ArgumentNullException("scriptDir");
            }

            if (errorSet == null)
            {
                throw new ArgumentNullException("errorSet");
            }

            if (validateSetting == null)
            {
                throw new ArgumentNullException("validateSetting");
            }

            if (!Directory.Exists(scriptDir))
            {
                throw new DirectoryNotFoundException(scriptDir);
            }

            validateSetting.VerifySetting();
            
            XmlScriptValidationScope scope = validateSetting.ValidationScope;

            string[] subFiles = Directory.GetFiles(
                scriptDir, "*" + XmlScriptFile.Extension, SearchOption.AllDirectories);
            XmlScriptFile mergedScript = new XmlScriptFile();

            long id = 0;
            foreach (string file in subFiles)
            {
                XmlScriptFile script = new XmlScriptFile();
                script.Load(file, contentController);
                if (mergedScript.Language == Language.Neutral)
                {
                    mergedScript.Language = script.Language;
                }
                else if (mergedScript.Language != script.Language)
                {
                    throw new InvalidDataException(Helper.NeutralFormat("Inconsistent langage in {0}", file));
                }

                if (scope != XmlScriptValidationScope.None)
                {
                    script.PosSet = validateSetting.PosSet;
                    script.PhoneSet = validateSetting.PhoneSet;

                    script.Validate(validateSetting);
                    script.Remove(GetNeedDeleteItemIds(script.ErrorSet));
                }

                errorSet.Merge(script.ErrorSet);
                foreach (ScriptItem item in script.Items)
                {
                    item.Id = resetId ? Helper.NeutralFormat("{0:D10}", ++id) : item.Id;

                    ErrorSet addErrors = new ErrorSet();
                    if (!mergedScript.Add(item, addErrors, false))
                    {
                        // Added failed
                        errorSet.Merge(addErrors);
                    }
                }
            }

            return mergedScript;
        }