c#中不区分大小写的XML解析器
Posted
技术标签:
【中文标题】c#中不区分大小写的XML解析器【英文标题】:Case insensitive XML parser in c# 【发布时间】:2012-03-09 05:42:20 【问题描述】:你对 XML 所做的一切都是区分大小写的,我知道。
但是,现在我发现自己处于一种情况,如果我以某种方式使 xml 名称/属性识别不区分大小写,我正在编写的软件将产生更少的错误。不区分大小写的 XPath 将是上帝派来的。
有没有简单的方法/库在 c# 中做到这一点?
【问题讨论】:
不太可能。但你可以做XElement.Parse(xmlText.Tolower())
一个 XMl 文档可以有两个 不同的 元素,分别命名为:MyName
和 myName
——它们旨在不同。将它们转换/视为同名是一个错误,可能会产生严重后果。
【参考方案1】:
一个 XMl 文档可以有两个不同的元素,分别命名为:MyName
和 myName
——它们是不同的。将它们转换/视为同名是一个错误,可能会产生严重后果。
如果不是上述情况,那么这里有一个更精确的解决方案,使用 XSLT 将文档处理成只有小写元素名称和小写属性名称的文档:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vUpper" select=
"'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="vLower" select=
"'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[name()=local-name()]" priority="2">
<xsl:element name="translate(name(), $vUpper, $vLower)"
namespace="namespace-uri()">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
<xsl:template match="*" priority="1">
<xsl:element name=
"substring-before(name(), ':'):translate(local-name(), $vUpper, $vLower)"
namespace="namespace-uri()">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*[name()=local-name()]" priority="2">
<xsl:attribute name="translate(name(), $vUpper, $vLower)"
namespace="namespace-uri()">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="@*" priority="1">
<xsl:attribute name=
"substring-before(name(), ':'):translate(local-name(), $vUpper, $vLower)"
namespace="namespace-uri()">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
当此转换应用于任何 XML 文档时,例如这个:
<authors xmlns:user="myNamespace">
<?ttt This is a PI ?>
<Author xmlns:user2="myNamespace2">
<Name idd="VH">Victor Hugo</Name>
<user2:Name idd="VH">Victor Hugo</user2:Name>
<Nationality xmlns:user3="myNamespace3">French</Nationality>
</Author>
<!-- This is a very long comment the purpose is
to test the default stylesheet for long comments-->
<Author Period="classical">
<Name>Sophocles</Name>
<Nationality>Greek</Nationality>
</Author>
<author>
<Name>Leo Tolstoy</Name>
<Nationality>Russian</Nationality>
</author>
<Author>
<Name>Alexander Pushkin</Name>
<Nationality>Russian</Nationality>
</Author>
<Author Period="classical">
<Name>Plato</Name>
<Nationality>Greek</Nationality>
</Author>
</authors>
生成所需的正确结果(元素和属性名称转换为小写):
<authors><?ttt This is a PI ?>
<author>
<name idd="VH">Victor Hugo</name>
<user2:name xmlns:user2="myNamespace2" idd="VH">Victor Hugo</user2:name>
<nationality>French</nationality>
</author><!-- This is a very long comment the purpose is
to test the default stylesheet for long comments-->
<author period="classical">
<name>Sophocles</name>
<nationality>Greek</nationality>
</author>
<author>
<name>Leo Tolstoy</name>
<nationality>Russian</nationality>
</author>
<author>
<name>Alexander Pushkin</name>
<nationality>Russian</nationality>
</author>
<author period="classical">
<name>Plato</name>
<nationality>Greek</nationality>
</author>
</authors>
一旦将文档转换为所需的形式,您就可以对转换后的文档执行任何所需的处理。
【讨论】:
是否有任何C++代码可以将XML属性和节点转换为大写字母或小写字母? @DavidAlex:您需要调用可以在 C++ 中调用的 XSLT 处理器的函数。您需要确定哪一个最适合您——MSXML/MSXSL、Saxon/C 或其他产品。然后阅读所选产品的文档,理解代码示例。 @DimitreNovatchev,我想使用 MSXML/MSXSL。您是否有读取 xml 并运行 xsl 转换以将属性和节点转换为大写字母或小写字母的示例代码?我对 XSL 转换很陌生,需要帮助!谢谢 @DavidAlex -- 你可以使用微软的 MSXML6 SDK -- 可以从这里下载:microsoft.com/en-us/download/details.aspx?id=3988。这应该包含主要类型/类的大量文档以及如何从不同的编程语言调用它们的方法的示例。有一个较旧的 -- 适用于 MSXML4,可以在此处下载:microsoft.com/en-us/download/details.aspx?id=19662 其中任何一个都应该满足您的需要和要求 @DimitreNovaatchev,您提供的 xslt 会导致根元素上的所有属性都丢失。即使在上面的示例中也显示了这一点。为了不让它们丢失,我会在 xlst 中进行哪些更改?【参考方案2】:您可以创建不区分大小写的方法(可用性扩展),例如:
public static class XDocumentExtensions
public static IEnumerable<XElement> ElementsCaseInsensitive(this XContainer source,
XName name)
return source.Elements()
.Where(e => e.Name.Namespace == name.Namespace
&& e.Name.LocalName.Equals(name.LocalName, StringComparison.OrdinalIgnoreCase));
【讨论】:
【参考方案3】:XML 是文本。在加载到您正在使用的任何解析器之前,只需 ToLower
即可。
只要您不必针对架构进行验证并且不介意值全部为小写,这应该可以正常工作。
事实上,任何 XML 解析器都会区分大小写。如果不是,它就不是 XML 解析器。
【讨论】:
但你可能不想ToLower
你的价值观
@Chad - 可能。我确实在我的回答中提出了这个警告。
我已经想到了。在大多数情况下,这会起作用,除了有时字段可能包含信息,我希望在这些信息中保留案例。例如,外部世界的密码、哈希和其他东西。另一方面,我真的不需要区分 xhtml 中的 Name 和 name 属性
XHTML 中有Name
属性,还是name
?
有时是一个,有时是另一个。这就是我遇到的问题。【参考方案4】:
我会首先将所有标签和属性名称转换为小写,保持值不变,使用SAX
解析,即。 XmlTextReader
。
【讨论】:
【参考方案5】:我使用另一种解决方案。人们想要这个的原因是因为您不想在属性中复制类文件中的属性名称。所以我要做的是为所有属性添加一个自定义属性:
[AttributeUsage(AttributeTargets.Property)]
public class UsePropertyNameToLowerAsXmlElementAttribute: XmlElementAttribute
public UsePropertyNameToLowerAsXmlElementAttribute([CallerMemberName] string propertyName = null)
: base(propertyName?.ToLower())
这样,XML 序列化程序可以将小写属性映射到 CamelCased 类。
类上的属性仍然有一个装饰器,它表示某些东西是不同的,但是您没有用名称标记每个属性的开销:
public class Settings
[UsePropertyNameToLowerAsXmlElement]
public string VersionId get; set;
[UsePropertyNameToLowerAsXmlElement]
public int? ApplicationId get; set;
【讨论】:
以上是关于c#中不区分大小写的XML解析器的主要内容,如果未能解决你的问题,请参考以下文章
解析器错误消息:无法识别的属性“targetFramework”。请注意,属性名称区分大小写