C# XmlReader 无法读取“<”作为 InnerXmlText
C# XmlReader can't read "<" as InnerXmlText
我写了一个 XML-Parser,在 InnerXml 中我得到了这样的文本:
<Name ...><<interface>>Employee</Name>
<!-- "<<interface>>Employee" is the InnerXml Text and I need it as string -->
我阅读文本的代码如下所示:
string getName(XmlReader reader)
{
string className;
while (reader.Read())
{
if (reader.HasValue)
{
className += reader.Value;
}
}
return className;
}
但是在我的 XmlTextReader 读取这一行之后,我遇到了一个异常:
Nachricht:
System.Xml.XmlException : Ein Name darf nicht mit dem Zeichen '<', hexadezimaler Wert 0x3C, beginnen.
这意味着'<'字符不可读或文本不能以'<'字符开头。
谁能解释一下这个吗?
基本上它自己转换成这个(在 XML-File 中):
<Name...><<interface>>Employee</Name> <!-- instead of <<interface>> -->
整个 .grapml 文件(它是一种不同的 xml 表示法):
(在 y:NodeLabel)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.19.1-->
<key for="port" id="d0" yfiles.type="portgraphics"/>
<key for="port" id="d1" yfiles.type="portgeometry"/>
<key for="port" id="d2" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d3"/>
<key attr.name="description" attr.type="string" for="node" id="d4"/>
<key for="node" id="d5" yfiles.type="nodegraphics"/>
<key for="graphml" id="d6" yfiles.type="resources"/>
<key attr.name="url" attr.type="string" for="edge" id="d7"/>
<key attr.name="description" attr.type="string" for="edge" id="d8"/>
<key for="edge" id="d9" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<node id="n0">
<data key="d5">
<y:UMLClassNode>
<y:Geometry height="116.0" width="131.0" x="1301.3333333333333" y="41.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="33.40234375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="82.052734375" x="24.4736328125" xml:space="preserve" y="3.0"><<interface>>
Employee</y:NodeLabel>
<y:UML clipContent="true" constraint="" hasDetailsColor="false" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel xml:space="preserve">+name:string
+age:int</y:AttributeLabel>
<y:MethodLabel xml:space="preserve">getName(value:string):String
getTitle():String
getStaffNo():Int
getRoom():String
getPhone()</y:MethodLabel>
</y:UML>
</y:UMLClassNode>
</data>
</node>
</graph>
<data key="d6">
<y:Resources/>
</data>
</graphml>
我的单元测试代码如下所示:
public T checkInterfaceOrClass<T> (XmlReader reader, string filepath) where T : BaseModel
{
//reader.Settings.IgnoreWhitespace = true;
while (reader.Read())
{
if (getName(reader).Contains("interface"))
{
InterfaceModel interfaceModel = new InterfaceModel(getName(reader));
return (T)Convert.ChangeType(interfaceModel, typeof(InterfaceModel));
}
else
{
ClassObject classModel = new ClassObject(getName(reader));
return (T)Convert.ChangeType(classModel, typeof(ClassObject));
}
}
}
return null;
}
根据评论,我写了一个简单的代码片段(使用 ReadToDescendant
方法跳过整个文件结构),ReadElementContentAsString
method,效果很好
var xmlReader = XmlReader.Create("...");
bool canRead = xmlReader.ReadToDescendant("y:NodeLabel");
if (canRead)
{
var content = xmlReader.ReadElementContentAsString();
}
元素内容为(字符串里面有一个\n
)
<<interface>>
Employee
您可以很容易地解析这个字符串并得到一个 class 名称,有或没有 <<interface>>
。
仅使用 Read
方法会得到相同的结果,如此处
bool canRead = xmlReader.ReadToDescendant("y:NodeLabel");
if (canRead)
{
while (xmlReader.Read())
{
var content = xmlReader.Value;
}
}
根据您使用单元测试编辑进行更新。您不需要使用 MoveToContent
,因为 ReadElementContentAsString
已经读取了当前元素下的内容。但主要问题是你多次调用这个方法,因为
This method reads the start tag, the contents of the element, and
moves the reader past the end element tag.
所以,第二次调用很可能失败了。您只需要读取一次内容然后解析它,而不是读取多次
我写了一个 XML-Parser,在 InnerXml 中我得到了这样的文本:
<Name ...><<interface>>Employee</Name>
<!-- "<<interface>>Employee" is the InnerXml Text and I need it as string -->
我阅读文本的代码如下所示:
string getName(XmlReader reader)
{
string className;
while (reader.Read())
{
if (reader.HasValue)
{
className += reader.Value;
}
}
return className;
}
但是在我的 XmlTextReader 读取这一行之后,我遇到了一个异常:
Nachricht:
System.Xml.XmlException : Ein Name darf nicht mit dem Zeichen '<', hexadezimaler Wert 0x3C, beginnen.
这意味着'<'字符不可读或文本不能以'<'字符开头。 谁能解释一下这个吗? 基本上它自己转换成这个(在 XML-File 中):
<Name...><<interface>>Employee</Name> <!-- instead of <<interface>> -->
整个 .grapml 文件(它是一种不同的 xml 表示法): (在 y:NodeLabel)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.19.1-->
<key for="port" id="d0" yfiles.type="portgraphics"/>
<key for="port" id="d1" yfiles.type="portgeometry"/>
<key for="port" id="d2" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d3"/>
<key attr.name="description" attr.type="string" for="node" id="d4"/>
<key for="node" id="d5" yfiles.type="nodegraphics"/>
<key for="graphml" id="d6" yfiles.type="resources"/>
<key attr.name="url" attr.type="string" for="edge" id="d7"/>
<key attr.name="description" attr.type="string" for="edge" id="d8"/>
<key for="edge" id="d9" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<node id="n0">
<data key="d5">
<y:UMLClassNode>
<y:Geometry height="116.0" width="131.0" x="1301.3333333333333" y="41.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="33.40234375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="82.052734375" x="24.4736328125" xml:space="preserve" y="3.0"><<interface>>
Employee</y:NodeLabel>
<y:UML clipContent="true" constraint="" hasDetailsColor="false" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel xml:space="preserve">+name:string
+age:int</y:AttributeLabel>
<y:MethodLabel xml:space="preserve">getName(value:string):String
getTitle():String
getStaffNo():Int
getRoom():String
getPhone()</y:MethodLabel>
</y:UML>
</y:UMLClassNode>
</data>
</node>
</graph>
<data key="d6">
<y:Resources/>
</data>
</graphml>
我的单元测试代码如下所示:
public T checkInterfaceOrClass<T> (XmlReader reader, string filepath) where T : BaseModel
{
//reader.Settings.IgnoreWhitespace = true;
while (reader.Read())
{
if (getName(reader).Contains("interface"))
{
InterfaceModel interfaceModel = new InterfaceModel(getName(reader));
return (T)Convert.ChangeType(interfaceModel, typeof(InterfaceModel));
}
else
{
ClassObject classModel = new ClassObject(getName(reader));
return (T)Convert.ChangeType(classModel, typeof(ClassObject));
}
}
}
return null;
}
根据评论,我写了一个简单的代码片段(使用 ReadToDescendant
方法跳过整个文件结构),ReadElementContentAsString
method,效果很好
var xmlReader = XmlReader.Create("...");
bool canRead = xmlReader.ReadToDescendant("y:NodeLabel");
if (canRead)
{
var content = xmlReader.ReadElementContentAsString();
}
元素内容为(字符串里面有一个\n
)
<<interface>>
Employee
您可以很容易地解析这个字符串并得到一个 class 名称,有或没有 <<interface>>
。
仅使用 Read
方法会得到相同的结果,如此处
bool canRead = xmlReader.ReadToDescendant("y:NodeLabel");
if (canRead)
{
while (xmlReader.Read())
{
var content = xmlReader.Value;
}
}
根据您使用单元测试编辑进行更新。您不需要使用 MoveToContent
,因为 ReadElementContentAsString
已经读取了当前元素下的内容。但主要问题是你多次调用这个方法,因为
This method reads the start tag, the contents of the element, and moves the reader past the end element tag.
所以,第二次调用很可能失败了。您只需要读取一次内容然后解析它,而不是读取多次