C#中的不区分大小写的XML解析器

15

你做的每一件事情都是区分大小写的,我知道。

但是,现在我发现自己处于这样一种情况中,如果某种方式使xml名称/属性识别不区分大小写,我编写的软件将产生更少的错误。不区分大小写的XPath会拯救我。

在C#中有没有简单的方法/库可以实现这一点?


不太可能。但是你可以使用 XElement.Parse(xmlText.Tolower()) - H H
一个XML文档可以有两个不同的元素,分别命名为:MyNamemyName--它们被设计成不同的。将它们转换/处理为相同的名称是一个错误,可能会产生严重的后果。 - Dimitre Novatchev
5个回答

15

一个XML文档可以有两个不同的元素名,分别为MyNamemyName,它们被认为是不同的。把它们转换/处理成相同的名称是一个错误,可能会产生严重后果。

如果上述情况不是这样的话,那么这里有一个更精确的解决方案,使用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 属性和节点转换为大写或小写字母? - David Alex
@DavidAlex:你需要调用一个可以在C++中调用的XSLT处理器的函数。你需要确定哪个是最适合你的——MSXML/MSXSL、Saxon/C或其他产品。然后阅读所选择产品的文档并理解代码示例。 - Dimitre Novatchev
@DimitreNovatchev,我想使用MSXML/MSXSL。你有没有读取XML并运行XSL转换以将属性和节点转换为大写字母或小写字母的示例代码?我对XSL转换相当新,并需要帮助!谢谢。 - David Alex
1
@DavidAlex -- 你可以使用微软的MSXML6 SDK -- 它可以从这里下载:https://www.microsoft.com/en-us/download/details.aspx?id=3988。这应该包含主要类型/类的广泛文档和如何从不同的编程语言调用它们的方法的示例。还有一个旧版本的MSXML4,可以在这里下载:https://www.microsoft.com/en-us/download/details.aspx?id=19662其中任何一个都应该符合您的需求和要求。 - Dimitre Novatchev
@DimitreNovatchev,您提供的XSLT会导致根元素上的所有属性丢失。即使在您上面的示例中也是如此。我应该在XSLT中做哪些更改才能避免它们丢失? - tig
@tig,没有属性“丢失”。你看到的是一些在元素后代中未使用的命名空间。这并没有什么不好 :) 但是,如果您必须在转换结果中保留这些命名空间,您可以在任何一个<xsl:apply-templates select="node()|@*"/>之前添加此内容:<xsl:copy-of select="namespace::*"/> - Dimitre Novatchev

13

您可以创建不区分大小写的方法(通过扩展以提高可用性),例如:

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));
    }
}

6

XML是文本。在加载到您正在使用的任何解析器之前,只需将其 ToLower

只要您不必针对模式进行验证并且不介意值全部为小写,这应该可以正常工作。


事实上,任何XML解析器都会区分大小写。如果不是这样,它就不会成为XML解析器。


14
但是你可能不想将你的值转换为小写(使用ToLower)。 - CaffGeek
1
@Chad - 可能吧。我在我的回答中提到了那个警告。 - Oded
我已经考虑过这个问题。在大多数情况下,这应该是有效的,但有时字段可能包含信息,我希望它们的大小写被保留,例如密码、哈希和其他用于外部世界的内容。另一方面,在xhtml中,我并不真正需要区分Name和name属性。 - Arsen Zahray
在XHTML中,是有Name属性还是name属性? - John Saunders
有时是一个,有时是另一个。这就是我遇到的问题。 - Arsen Zahray
这种完全的小写化“破坏”了某些元素。例如,“aName”,“AName”和“anamE”都变成了“aname”。这个想法的第二个大问题是它不仅改变名称,还改变文本节点和属性的内容。它还改变了命名空间的值,使得XML文档完全无法使用。一个快速的例子:将"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"转换为"xmlns:xsl="http://www.w3.org/1999/xsl/transform",那么这个XML文档(一个语法上有效的XSLT样式表)现在被XSLT处理器拒绝了。 - Dimitre Novatchev

3

我使用另一种解决方案。人们想要这样做的原因是因为你不想在类文件中的属性和属性中重复使用名称。所以我的做法是为所有属性添加一个自定义属性:


OriginalAnswerAttribute
[AttributeUsage(AttributeTargets.Property)]
public class UsePropertyNameToLowerAsXmlElementAttribute: XmlElementAttribute
{
    public UsePropertyNameToLowerAsXmlElementAttribute([CallerMemberName] string propertyName = null)
    : base(propertyName?.ToLower())
    {
    }
}

这样XML序列化程序就可以将小写属性映射到驼峰命名的类。

类上的属性仍然有一个装饰器,说明某些东西不同,但您没有标记每个属性名称的开销:

最初的回答:

public class Settings
{
    [UsePropertyNameToLowerAsXmlElement]
    public string VersionId { get; set; }

    [UsePropertyNameToLowerAsXmlElement]
    public int? ApplicationId { get; set; }
}

1

我会从转换所有标签和属性名称为小写开始,保留值不变,使用 SAX 解析,即使用 XmlTextReader


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接