G
Guest
Hi.
Using VS2005, .NET 2.0.
I have an xml document that I want to go through and set the values on
attributes of elements. The elements are complex types defined in my schema
(xsd) files.
I can iterate the document and get my XmlType and XmlBaseType values just
fine. However, as soon as I call SetValue to write to an attribute, the
XmlType is always null so I can no longer test the rest of the elements in
the document.
Following are the Xsd, Xml and Program.cs to recreate the problem.
-- TestXPathNavBugSchemaBase.xsd --
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mine="http://mytest.ca/mine" targetNamespace="http://mytest.ca/mine"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="OrderBase">
<xs:annotation>
<xs:documentation>Base Schema for Orders</xs:documentation>
</xs:annotation>
<xs:attribute name="Name" type="xs:string" use="required"/>
<xs:attribute name="Updatable" type="xs:boolean" use="required"
fixed="true"/>
</xs:complexType>
<xs:complexType name="PurchaseOrderBase">
<xs:complexContent>
<xs:extension base="mine:OrderBase">
<xs:attribute name="PurchaseOrderNumber" type="xs:string" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="OrderItemBase">
<xs:annotation>
<xs:documentation>Base Schema for Order items</xs:documentation>
</xs:annotation>
<xs:attribute name="ItemType" type="xs:string" use="required"/>
<xs:attribute name="ItemDescription" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="PurchaseOrderItemBase">
<xs:complexContent>
<xs:extension base="mine:OrderItemBase">
<xs:attribute name="PurchaseOrderNumber" type="xs:string" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
-- TestXPathNavBugSchema.xsd --
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mine="http://mytest.ca/mine" targetNamespace="http://mytest.ca/mine"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:include schemaLocation="TestXPathNavBugSchemaBase.xsd"/>
<xs:complexType name="AutoPartsPurchaseOrderType">
<xs:complexContent>
<xs:extension base="mineurchaseOrderBase">
<xs:sequence>
<xs:element name="Header" type="mineurchaseOrderItemBase"/>
<xs:element name="Body" type="mineurchaseOrderItemBase"/>
<xs:element name="Footer" type="mineurchaseOrderItemBase"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="AutoPartsPurchaseContract">
<xs:complexType>
<xs:sequence>
<xs:element name="PurchaseOrders" type="mine:AutoPartsPurchaseOrderType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
-- TestXPathNavBug.xml --
<?xml version="1.0" encoding="UTF-8"?>
<AutoPartsPurchaseContract xmlns="http://mytest.ca/mine"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mytest.ca/mine TestXPathNavBugSchema.xsd">
<PurchaseOrders Updatable="true" Name="" PurchaseOrderNumber="">
<Header ItemType="" ItemDescription="" PurchaseOrderNumber="" />
<Body ItemType="" ItemDescription="" PurchaseOrderNumber="" />
<Footer ItemType="" ItemDescription="" PurchaseOrderNumber="" />
</PurchaseOrders>
</AutoPartsPurchaseContract>
-- Program.cs --
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Schema;
namespace TestXPathNavBug
{
class Program
{
static void Main(string[] args)
{
const string xmlFileName = @"..\..\TestXPathNavBug.xml";
//Load the xml with its xsd
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add("http://mytest.ca/mine",
@"..\..\TestXPathNavBugSchema.xsd");
settings.ValidationType = ValidationType.Schema;
XmlReader reader = XmlReader.Create(xmlFileName, settings);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
//Create an XPathNavigator
XPathNavigator xpath = doc.CreateNavigator();
// Start at the top
xpath.MoveToRoot();
//Modify the xml document
TraverseTree(xpath);
//Save
reader.Close();
doc.Save(xmlFileName);
Console.ReadKey();
}
private static void TraverseTree(XPathNavigator xpath)
{
//Process this node
if (xpath.NodeType == XPathNodeType.Element)
{
Console.WriteLine("Element: {0}", xpath.Name);
//See if this is one of our schema types
XmlSchemaType xmlBaseType = null;
XmlSchemaType xmlType = xpath.XmlType;
if (xmlType != null)
{
if (!string.IsNullOrEmpty(xmlType.Name))
Console.WriteLine(" XmlType: {0}", xmlType.Name);
xmlBaseType = xmlType.BaseXmlSchemaType;
if (!string.IsNullOrEmpty(xmlBaseType.Name))
Console.WriteLine(" XmlBaseType: {0}",
xmlBaseType.Name);
}
//These are the attributes we want to populate in the XML
file.
if (xmlBaseType != null
&& !string.IsNullOrEmpty(xmlBaseType.Name)
&& xmlBaseType.Name.Equals("OrderItemBase",
StringComparison.OrdinalIgnoreCase))
{
if (xpath.HasAttributes)
{
//Grab a clone to start navigating at this position
XPathNavigator navAttributes = xpath.Clone();
navAttributes.MoveToFirstAttribute();
do
{
Console.WriteLine(" Attribute: {0}, can edit?
{1}", navAttributes.Name, navAttributes.CanEdit);
string valueToSave = string.Empty;
switch (navAttributes.Name.ToLowerInvariant())
{
case "itemtype":
valueToSave = string.Format("{0}{1}",
navAttributes.Name, xmlType.Name);
break;
case "itemdescription":
valueToSave = string.Format("Describe
{0}{1}", navAttributes.Name, xmlType.Name);
break;
case "purchaseordernumber":
valueToSave =
DateTime.Now.Ticks.ToString();
break;
}
//TODO: This reproduces the bug.
/* If you call the SetValue, then the XmlTypes
are wiped out on
* subsequent Moves.
* */
if (!string.IsNullOrEmpty(valueToSave))
navAttributes.SetValue(valueToSave);
} while (navAttributes.MoveToNextAttribute());
}
}
}
//Go down the branch
if (xpath.HasChildren)
{
xpath.MoveToFirstChild();
do
{
TraverseTree(xpath);
} while (xpath.MoveToNext());
//Go back to the top of the branch
xpath.MoveToParent();
}
}
}
}
Using VS2005, .NET 2.0.
I have an xml document that I want to go through and set the values on
attributes of elements. The elements are complex types defined in my schema
(xsd) files.
I can iterate the document and get my XmlType and XmlBaseType values just
fine. However, as soon as I call SetValue to write to an attribute, the
XmlType is always null so I can no longer test the rest of the elements in
the document.
Following are the Xsd, Xml and Program.cs to recreate the problem.
-- TestXPathNavBugSchemaBase.xsd --
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mine="http://mytest.ca/mine" targetNamespace="http://mytest.ca/mine"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="OrderBase">
<xs:annotation>
<xs:documentation>Base Schema for Orders</xs:documentation>
</xs:annotation>
<xs:attribute name="Name" type="xs:string" use="required"/>
<xs:attribute name="Updatable" type="xs:boolean" use="required"
fixed="true"/>
</xs:complexType>
<xs:complexType name="PurchaseOrderBase">
<xs:complexContent>
<xs:extension base="mine:OrderBase">
<xs:attribute name="PurchaseOrderNumber" type="xs:string" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="OrderItemBase">
<xs:annotation>
<xs:documentation>Base Schema for Order items</xs:documentation>
</xs:annotation>
<xs:attribute name="ItemType" type="xs:string" use="required"/>
<xs:attribute name="ItemDescription" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="PurchaseOrderItemBase">
<xs:complexContent>
<xs:extension base="mine:OrderItemBase">
<xs:attribute name="PurchaseOrderNumber" type="xs:string" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
-- TestXPathNavBugSchema.xsd --
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mine="http://mytest.ca/mine" targetNamespace="http://mytest.ca/mine"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:include schemaLocation="TestXPathNavBugSchemaBase.xsd"/>
<xs:complexType name="AutoPartsPurchaseOrderType">
<xs:complexContent>
<xs:extension base="mineurchaseOrderBase">
<xs:sequence>
<xs:element name="Header" type="mineurchaseOrderItemBase"/>
<xs:element name="Body" type="mineurchaseOrderItemBase"/>
<xs:element name="Footer" type="mineurchaseOrderItemBase"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="AutoPartsPurchaseContract">
<xs:complexType>
<xs:sequence>
<xs:element name="PurchaseOrders" type="mine:AutoPartsPurchaseOrderType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
-- TestXPathNavBug.xml --
<?xml version="1.0" encoding="UTF-8"?>
<AutoPartsPurchaseContract xmlns="http://mytest.ca/mine"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mytest.ca/mine TestXPathNavBugSchema.xsd">
<PurchaseOrders Updatable="true" Name="" PurchaseOrderNumber="">
<Header ItemType="" ItemDescription="" PurchaseOrderNumber="" />
<Body ItemType="" ItemDescription="" PurchaseOrderNumber="" />
<Footer ItemType="" ItemDescription="" PurchaseOrderNumber="" />
</PurchaseOrders>
</AutoPartsPurchaseContract>
-- Program.cs --
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Schema;
namespace TestXPathNavBug
{
class Program
{
static void Main(string[] args)
{
const string xmlFileName = @"..\..\TestXPathNavBug.xml";
//Load the xml with its xsd
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add("http://mytest.ca/mine",
@"..\..\TestXPathNavBugSchema.xsd");
settings.ValidationType = ValidationType.Schema;
XmlReader reader = XmlReader.Create(xmlFileName, settings);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
//Create an XPathNavigator
XPathNavigator xpath = doc.CreateNavigator();
// Start at the top
xpath.MoveToRoot();
//Modify the xml document
TraverseTree(xpath);
//Save
reader.Close();
doc.Save(xmlFileName);
Console.ReadKey();
}
private static void TraverseTree(XPathNavigator xpath)
{
//Process this node
if (xpath.NodeType == XPathNodeType.Element)
{
Console.WriteLine("Element: {0}", xpath.Name);
//See if this is one of our schema types
XmlSchemaType xmlBaseType = null;
XmlSchemaType xmlType = xpath.XmlType;
if (xmlType != null)
{
if (!string.IsNullOrEmpty(xmlType.Name))
Console.WriteLine(" XmlType: {0}", xmlType.Name);
xmlBaseType = xmlType.BaseXmlSchemaType;
if (!string.IsNullOrEmpty(xmlBaseType.Name))
Console.WriteLine(" XmlBaseType: {0}",
xmlBaseType.Name);
}
//These are the attributes we want to populate in the XML
file.
if (xmlBaseType != null
&& !string.IsNullOrEmpty(xmlBaseType.Name)
&& xmlBaseType.Name.Equals("OrderItemBase",
StringComparison.OrdinalIgnoreCase))
{
if (xpath.HasAttributes)
{
//Grab a clone to start navigating at this position
XPathNavigator navAttributes = xpath.Clone();
navAttributes.MoveToFirstAttribute();
do
{
Console.WriteLine(" Attribute: {0}, can edit?
{1}", navAttributes.Name, navAttributes.CanEdit);
string valueToSave = string.Empty;
switch (navAttributes.Name.ToLowerInvariant())
{
case "itemtype":
valueToSave = string.Format("{0}{1}",
navAttributes.Name, xmlType.Name);
break;
case "itemdescription":
valueToSave = string.Format("Describe
{0}{1}", navAttributes.Name, xmlType.Name);
break;
case "purchaseordernumber":
valueToSave =
DateTime.Now.Ticks.ToString();
break;
}
//TODO: This reproduces the bug.
/* If you call the SetValue, then the XmlTypes
are wiped out on
* subsequent Moves.
* */
if (!string.IsNullOrEmpty(valueToSave))
navAttributes.SetValue(valueToSave);
} while (navAttributes.MoveToNextAttribute());
}
}
}
//Go down the branch
if (xpath.HasChildren)
{
xpath.MoveToFirstChild();
do
{
TraverseTree(xpath);
} while (xpath.MoveToNext());
//Go back to the top of the branch
xpath.MoveToParent();
}
}
}
}