使用XDocument创建模式有序XML

时间:2010-09-17 16:02:59

标签: c# xsd linq-to-xml

我目前正在尝试找到一种以架构顺序向现有xml文档添加一些额外元素的方法。

xml附加了一个模式,但我一直无法找到一种方法来使XDocument操作符合模式顺序。

示例模式提取

<xs:element name="control" minOccurs="1" maxOccurs="1">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="applicationId" type="xs:unsignedByte" minOccurs="1" maxOccurs="1" />
      <xs:element name="originalProcId" type="xs:unsignedByte" minOccurs="0" maxOccurs="1" />
      <xs:element name="dateCreated" type="xs:date" minOccurs="0" maxOccurs="1" />
      <xs:element name="requestId" type="xs:string" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

示例xml输入

<?xml version="1.0" encoding="utf-8" ?>
<someDocument xmlns="urn:Test">
  <control>
    <applicationId>19</applicationId>
    <dateCreated>2010-09-18</dateCreated>
  </control>
  <body />
</someDocument>

示例代码段

XDocument requestDoc = XDocument.Load("control.xml");

XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("urn:MarksTest", XmlReader.Create("body.xsd"));

// Valid according to the schema
requestDoc.Validate(schemas, null, true);

XElement controlBlock = requestDoc.Descendants("control").First();

controlBlock.Add(new XElement("originalProcId", "2"));
controlBlock.Add(new XElement("requestId", "TestRequestId"));

// Not so valid
controlBlock.Validate(controlBlock.GetSchemaInfo().SchemaElement, schemas, null, true);

我需要添加OriginalProcId和requestId元素,但是它们需要转到Control元素中的特定位置,而不仅仅是作为最后一个子元素。当然,这不像在前一个元素上执行AddAfterSelf那么容易,因为我只是害羞的100个可选元素,可能是也可能不在xml中。

我已经尝试使用Validate method将架构验证信息集嵌入到XDocument中,我认为这可能会起到作用,但它似乎对元素插入位置没有影响。

有办法做到这一点还是我运气不好?

1 个答案:

答案 0 :(得分:0)

我最终用一些xlst做了这个,它将节点转换为自己但是有序,这里是代码

// Create a reader for the existing control block
var controlReader = controlBlock.CreateReader();

// Create the writer for the new control block
XmlWriterSettings settings = new XmlWriterSettings {
    ConformanceLevel = ConformanceLevel.Fragment, Indent = false, OmitXmlDeclaration = false };

StringBuilder sb = new StringBuilder();
var xw = XmlWriter.Create(sb, settings);

// Load the style sheet from the assembly
Stream transform = Assembly.GetExecutingAssembly().GetManifestResourceStream("ControlBlock.xslt");
XmlReader xr = XmlReader.Create(transform);

// Load the style sheet into the XslCompiledTransform
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xr);

// Execute the transform
xslt.Transform(controlReader, xw);

// Swap the old control element for the new one
controlBlock.ReplaceWith(XElement.Parse(sb.ToString()));