Modifying namespace in XML document programmatically

Modifying namespace in XML document programmatically

I needed to validate an XML document with a given XSD document. Seems easy enough… so let’s have a look at the schema first:

<?xml version="1.0" encoding="utf-8"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"                            xmlns="http://my.namespace"                           elementFormDefault="qualified"                            targetNamespace="http://my.namespace">   <xs:element name="customer">       <xs:complexType>           <xs:sequence>             <xs:element name="firstname" type="xs:string" />             <xs:element name="lastname" type="xs:string" />             <xs:element name="age" type="xs:integer" />           </xs:sequence>       </xs:complexType>   </xs:element></xs:schema>

The XML instance is:

<?xml version="1.0" encoding="utf-8" ?><customer>  <firstname>Homer</firstname>  <lastname></lastname>  <age>36</age></customer> 

The code is straightforward:

static void Main(string[] args){  // Load the xml document  XDocument source = XDocument.Load(@"instance.xml");  // Load the schema  XmlSchemaSet xmlSchemaSet = new XmlSchemaSet();  xmlSchemaSet.Add(null, XmlReader.Create(@"customer.xsd"));  // Validate  try { source.Validate(xmlSchemaSet, ValidationCallback, true); }  catch (Exception ex) { Console.WriteLine(ex.Message); }}static void ValidationCallback(object sender,     System.Xml.Schema.ValidationEventArgs e){  Console.WriteLine(string.Format("[{0}] {1}", e.Severity, e.Message));} 

If you run this, no errors are thrown so it seems to validate. To be sure, let’s change the age in an invalid value:

<Age>invalid!</Age>

and test again. Well… actually, no validation error is thrown in this case either… what’s going on here?

Actually, the XML is not validated at all, because it’s not in the same namespace (http://my.namespace) as the schema definition. This is very dangerous, as we might easily get mislead by thinking that it validates because no errors are thrown. So how do we solve it?

We could ask the sender to provide the correct namespace in the XML file – this would be the best solution because then it would just work – if you try to validate the following XML:

<?xml version="1.0" encoding="utf-8" ?><customer xmlns="http://my.namespace">  <firstname>Homer</firstname>  <lastname></lastname>  <age>invalid</age></customer>

…then the validation error is thrown, because the namespaces now match:

Unfortunately, it is not always possible to change the XML file, so how can we bypass this namespace conflict? If appears that if we would change the namespace in the loaded XML document to the one we are using in our schema, the conflict is resolved. A first attempt may be:

// Load the xml documentXDocument source = XDocument.Load(@"instance.xml");// Change namespace to reflect schema namespacesource.Root.SetAttributeValue("xmlns", "http://my.namespace");// Load the schemaXmlSchemaSet xmlSchemaSet = new XmlSchemaSet();xmlSchemaSet.Add(null, XmlReader.Create(@"customer.xsd"));// Validatetry { source.Validate(xmlSchemaSet, ValidationCallback, true); }catch (Exception ex) { Console.WriteLine(ex.Message); } 

If we run this, the validation error is still not thrown, so setting the namespace attribute is not enough. The reason is that once the XDocument is loaded, every element in the tree gets prefixed with the namespace name. So we need to change them all, and so I wrote the following method that does this:

static void Main(string[] args){  // Load the xml document  XDocument source = XDocument.Load(@"instance.xml");  // Change namespace to reflect schema namespace  source = SetNamespace(source,"http://my.namespace");  // Load the schema  XmlSchemaSet xmlSchemaSet = new XmlSchemaSet();  xmlSchemaSet.Add(null, XmlReader.Create(@"customer.xsd"));  // Validate  try { source.Validate(xmlSchemaSet, ValidationCallback, true); }  catch (Exception ex) { Console.WriteLine(ex.Message); }}public static XDocument SetNamespace(XDocument source, XNamespace xNamespace){  foreach (XElement xElement in source.Descendants())  {    // First make sure that the xmlns-attribute is changed    xElement.SetAttributeValue("xmlns", xNamespace.NamespaceName);    // Then also prefix the name of the element with the namespace    xElement.Name = xNamespace + xElement.Name.LocalName;  }  return source;}static void ValidationCallback(object sender,     System.Xml.Schema.ValidationEventArgs e){  Console.WriteLine(string.Format("[{0}] {1}", e.Severity, e.Message));} 

The SetNameSpace method will set the corrrect namespace for each element in the XDocument. And if we run it now, the validation error is thrown again because the namespace in the XDocument has been modified and matches the schema namespace.

Related

Parsing large XML filesIn "C#"

Strategy patternIn "C#"

A reference architecture (part 7)In "Architecture"

3 thoughts on “Modifying namespace in XML document programmatically”

  1. Janez says:

    November 18, 2010 at 4:30 pm

    Thanks, a working solution to a problem that took the better part of my day. :-)

    Reply

  2. Jim says:

    July 3, 2013 at 4:58 pm

    This solution was very hard to fine…thanks so much for posting it.

    Reply

  3. Mike says:

    June 19, 2015 at 3:51 pm

    This was very helpful and got me past some serious frustration! I was changing a child element tree to match a parent namespace, but I did not want to have the extra size of including the SetAttributeValue on all elements. My change was a change from one default namespace to another existing and prefixed one. This did the trick for me. Below are some minor adjustments that might be useful to others in some cases.

    public static XDocument SetNamespace(XDocument source, XNamespace original, XNamespace target)
    {
    //First change the element name (and namespace)
    foreach (XElement xElement in source.Descendants().Where(x => x.Name.Namespace == original))
    xElement.Name = target + xElement.Name.LocalName;

    //Second, remove the default namespace attribute.
    foreach (XElement xElement in source.Descendants().Where(x => x.Attributes().Where(y => y.Name == “xmlns”).Count() > 0))
    xElement.Attribute(“xmlns”).Remove();

    return source;
    }

    Reply

Leave a Reply

时间: 2024-11-10 05:12:39

Modifying namespace in XML document programmatically的相关文章

[翻译][Ruby教程]Nokogiri - 解析HTML/XML文档 / Parsing an HTML/XML Document

From a String From a File From the Internet Parse Options Encoding 原文: Parsing an HTML/XML Document 解析HTML/XML文档 从字符串读取 We’ve tried to make this easy on you. Really! We’re here to make your life easier. 1 html_doc = Nokogiri::HTML("<html><bo

解决SoapFault (looks like we got no XML document)问题

今天在调试项目的时候出现下面的错误信息: SoapFault looks like we got no XML document (D:\phpStudy\WWW\self.shop.xunmall.com\components\Proxy.php:477) #0 D:\phpStudy\WWW\self.shop.xunmall.com\components\Proxy.php(477): SoapClient->__call('sendAllGoods', Array)#1 D:\phpSt

Spring出现Unexpected exception parsing XML document from class path resource [applicationBeans.xml]; nested exception is java.lang.NoClassDefFoundError: org/springframework/aop/TargetSource异常

在自学Spring4的过程中,遇到了棘手的异常,一直找不到问题所在,后来经过对每个过程进行逐一排查之后,发现少了一个jar包:spring-aop-4.0.0.RELEASE.jar.完整的异常信息如下: Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from clas

Error loading XML document: dwz.frag.xml 处理方式

问题:直接用IE打开index.html弹出一个对话框:Error loading XML document: dwz.frag.xml 方案一(已经验证): 转自:http://blog.csdn.net/wy542107493/article/details/7641064 原因:dwz.frag.xml是一个核心文件,需要加载才可以正常使用.用firefox打开就正常 解决:在web.xml(tomcat的或者应用的配置文件都可以)中加入 <mime-mapping> <exten

Line 23 in XML document from class path resource [spring-mvc.xml] is invalid; nested exception is org.xml.sax.SAXParseException:

今天在把自己的项目转为maven架构的时候,居然碰到了一个很奇葩的问题具体如下: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 23 in XML document from class path resource [spring-mvc.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cos-all-l

eclipse错误:Unable to read workbench state. Workbench UI layout will be reset.XML document structures

Unable to read workbench state. Workbench UI layout will be reset.XML document structures must start and end within the same entity. 错误提示是说:不能找到正式的工作台,工作台UI的布局将被重排! 上次卡住了,然后直接杀进程,关闭掉,今天打开的时候一直报这个错误. --------------------解决方案-------------------- 1,检查一下

解决SOAP错误[Client] looks like we got no XML document

由于服务器配置不规范等等原因都会导致此类错误,解决: http://my.oschina.net/cart/ class SoapClientNew extends SoapClient { public function __doRequest($request, $location, $action, $version, $one_way = 0) { $request = parent::__doRequest($request, $location, $action, $version,

SQL Server 2008 installation fails There was an error generating the XML document. Error code 0x84B10001.

SQL Server 2008 installation fails There was an error generating the XML document. Error code 0x84B10001. 在windows2008R2上用Administrator用房安装mssqlserver2008 时起到最后一步安装时出现错误: 生成XML错误,Error code 0x84B10001 百度搜索了一堆网站后,都不成功,后来查询了微软官方论坛也不靠谱啊...https://social

org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from URL

[报错] org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from URL [file:/F:/MyWorkspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/marbled-cat/WEB-INF/classes/spring-servlet.xm