2D游戏引擎制作:读取XML文件 4

读取XML文件 4


前言

  上次的XML解析器还有很多地方需要完善,本篇文章就相当于对上篇文章进行补充,终于不是删除所有进行重写了。
多说一句, visual studio中使用foreach自动补全的代码没办法直接用?比如这样:
这里写图片描述


正文

1、XML文件有一种节点的写法笔者之前一直没太在意,就是这种直接将字符串写在节点里:

<author name ="JI">  
    <age>22</age>  
</author>
可以改成:
<author name ="JI" age="22"/>  
没办法多属性的情况,比如:
<question id="1" name="问东问西一星期,走南走北两公里,心上心下比Tiny,下一句是?">  
    <option>一天一地Orz。</option>
    <option>看得心态要崩溃。</option>
    <option>代码多出六百倍。</option>
    <option>真的不会感觉累?</option>
</question>
可以改写成这种形式:
<option value="一天一地Orz"/>

所以没有为这种形式写解析,但在网上找了找发现有这种写法的文件真的很多,好,还是添上吧!
写在节点里的字符串应该被当做文本节点,但此节点只有内容,而且一个节点中只会出现一次文本,所以就将它简化成属性。
LLXMLNode类中添加方法wstring GetInnerText(){return innerText;};和属性wstring innerText;。
在LoadUnknown方法里添加到当首字符不为’<’的判断里:

else if(!nodeStack.empty())
{
    wchar_t* textStart = fileBuffer;
    while (*fileBuffer!=L'<')
    {
        fileBuffer++;
        bufferSize--;
        if (bufferSize == 0)
        {
            return false;
        }
    }
    wstring innerText = wstring(textStart, fileBuffer - textStart);//此处没有添加截取空字符的操作,可以自行写截取方法。格式化字符串的方法在下面。
    nodeStack.top()->SetInnerText(innerText);
}

XML应该允许下列情况(节点中既有文本又有子节点)吧!

<Game id="1">Text  
    <Node/>
</Game>

2、属性值可以使用单引号和双引号,上篇文章只做了双引号的判断,本文进行补充。
需要在判断*fileBuffer==L’”’后加*fileBuffer==L’ \’’即可,还要修改一下其他地方,需要判断单引号开始要单引号结束,前后对应才算格式正确。将在LoadProperty中判断是单引号还是双引号放在LoadFormatValue里进行比较,代码就不展示了。

3、进行转义字符格式化:
先定义wstringstream wsstream;

#include <sstream>
wstring LLXMLDocument::FormatWStringFromXML(wstring ws)
{
    wsstream.str(L"");//需要进行两步操作,只用clear的话wsstream内的保存的字符串是不变的。
    wsstream.clear();//需要清空缓存
    int curPos = 0;
    int wsSize = ws.size();
    while (curPos<wsSize)
    {
        if (ws[curPos] == L'&')
        {
            if (ws.substr(curPos,6)==L"&quot;")
            {
                wsstream << L'"';
                curPos += 6;
            }
            else if (ws.substr(curPos, 6) == L"&apos;")
            {
                wsstream << L'\'';
                curPos += 6;
            }
            else if (ws.substr(curPos, 5) == L"&amp;")
            {
                wsstream << L'&';
                curPos += 5;
            }
            else if (ws.substr(curPos, 4) == L"&lt;")
            {
                wsstream << L'<';
                curPos += 4;
            }
            else if (ws.substr(curPos, 4) == L"&gt;")
            {
                wsstream << L'>';
                curPos += 4;
            }
            else
            {
                wsstream << ws[curPos];
                curPos++;
            }
        }
        else
        {
            wsstream << ws[curPos];
            curPos++;
        }
    }
    return wsstream.str();
}

输出与上同理逆向。

4、保存节点和属性:

void LLXMLDocument::SaveNode(wofstream& file, LLXMLNode* node, int depth)
{
    for (int i=0;i<depth;i++)
    {
        file << L'\t';
    }
    file << L"<" + node->GetName() ;
    if (node->GetPropertyMap().size()!=0)
    {
        file << L" ";
        for (auto var : node->GetPropertyMap())
        {
            SaveProperty(file, var.second);
            file << L" ";
        }
    }
    bool tempBool = false;
    if (node->GetInnerText() != L""|| node->GetChildNodeList().size() > 0)
    {
        tempBool = true;
    }
    if (!tempBool)
    {
        file << L"/>"<< endl;
        return;
    }
    file <<L">"<< endl;
    if (node->GetInnerText() != L"")
    {
        for (int i = 0; i < depth+1; i++)
        {
            file << L'\t';
        }
        file << node->GetInnerText() << endl;
    }
    for (auto var : node->GetChildNodeList())
    {
        SaveNode(file, var,depth+1);
    }
    for (int i = 0; i < depth; i++)
    {
        file << L'\t';
    }
    file << L"</" << node->GetName() << L">"<<endl;
}

void LLXMLDocument::SaveProperty(wofstream & file, LLXMLProperty * llProperty)
{
    file << llProperty->GetName() << L"=" << L'"' << FormatWStringToXML(llProperty->GetValue()) << L'"';
}

真正保存时只要传入LLXMLDocument.SaveNode(file,rootNode,0)就可以了。


结束语

  暂时补充这么多,如果各位发现了哪里有错误和不足,请指正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值