简体   繁体   中英

Using XmlAttributeOverrides to change element names in object tree

I need to figure out how to rename elements and/or attributes in generated XML using values retrieved from the database as my element names.

For instance, here is a potential XML output from my current process:

<ArrayOfEntityTreeBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <EntityTreeBase EntityInfo="User">
    <Children>
      <EntityTreeBase EntityInfo="User Medication">
        <Properties>
          <EntityProperty CreatedDate="2013-11-14T16:41:12.75">
            <FieldName>Medication Name</FieldName>
            <Value>Celebrex</Value>
          </EntityProperty>
          <EntityProperty CreatedDate="2013-12-04T14:08:58.597">
            <FieldName>Medication Dosage</FieldName>
            <Value>20000MG</Value>
          </EntityProperty>
          <EntityProperty CreatedDate="2013-11-14T16:41:12.76">
            <FieldName>Medication Prescribed Date</FieldName>
            <Value>08/01/2013</Value>
          </EntityProperty>
        </Properties>
      </EntityTreeBase>
      <EntityTreeBase EntityInfo="User Medication">
        <Properties>
          <EntityProperty CreatedDate="2013-11-14T16:41:12.767">
            <FieldName>Medication Name</FieldName>
            <Value>Aspirin</Value>
          </EntityProperty>
          <EntityProperty CreatedDate="2013-11-14T16:41:12.77">
            <FieldName>Medication Dosage</FieldName>
            <Value>5 mg</Value>
          </EntityProperty>
          <EntityProperty CreatedDate="2013-11-14T16:41:12.78">
            <FieldName>Medication Prescribed Date</FieldName>
            <Value>09/01/2013</Value>
          </EntityProperty>
        </Properties>
      </EntityTreeBase>
      <EntityTreeBase EntityInfo="User Medication">
        <Properties>
          <EntityProperty CreatedDate="2013-11-14T16:41:12.783">
            <FieldName>Medication Name</FieldName>
            <Value>Celebrex</Value>
          </EntityProperty>
          <EntityProperty CreatedDate="2013-11-14T16:41:12.793">
            <FieldName>Medication Dosage</FieldName>
            <Value>50 mg twice a day</Value>
          </EntityProperty>
          <EntityProperty CreatedDate="2013-11-14T16:41:12.8">
            <FieldName>Medication Prescribed Date</FieldName>
            <Value>10/01/2013</Value>
          </EntityProperty>
        </Properties>
      </EntityTreeBase>
    </Children>
    <Properties>
      <EntityProperty CreatedDate="2013-12-03T13:48:03.45">
        <FieldName>User First Name</FieldName>
        <Value>John</Value>
      </EntityProperty>
      <EntityProperty CreatedDate="2013-12-03T11:36:31.423">
        <FieldName>User MI</FieldName>
        <Value>Q</Value>
      </EntityProperty>
      <EntityProperty CreatedDate="2013-11-19T09:56:44.66">
        <FieldName>User Last Name</FieldName>
        <Value>Public</Value>
      </EntityProperty>
      <EntityProperty CreatedDate="2013-11-14T16:41:12.803">
        <FieldName>User SSN</FieldName>
        <Value>111-22-3333</Value>
      </EntityProperty>
    </Properties>
  </EntityTreeBase>
</ArrayOfEntityTreeBase>

What I need to accomplish is this:

<UserInformation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <User>
    <UserMedications>
      <UserMedication>
        <MedicationProperties>
          <MedicationProperty CreatedDate="2013-11-14T16:41:12.75">
            <FieldName>Medication Name</FieldName>
            <Value>Celebrex</Value>
          </MedicationProperty>
          <MedicationProperty CreatedDate="2013-12-04T14:08:58.597">
            <FieldName>Medication Dosage</FieldName>
            <Value>20000MG</Value>
          </MedicationProperty>
          <MedicationProperty CreatedDate="2013-11-14T16:41:12.76">
            <FieldName>Medication Prescribed Date</FieldName>
            <Value>08/01/2013</Value>
          </MedicationProperty>
        </MedicationProperties>
      </UserMedication>
      <UserMedication>
        <MedicationProperties>
          <MedicationProperty CreatedDate="2013-11-14T16:41:12.767">
            <FieldName>Medication Name</FieldName>
            <Value>Aspirin</Value>
          </MedicationProperty>
          <MedicationProperty CreatedDate="2013-11-14T16:41:12.77">
            <FieldName>Medication Dosage</FieldName>
            <Value>5 mg</Value>
          </MedicationProperty>
          <MedicationProperty CreatedDate="2013-11-14T16:41:12.78">
            <FieldName>Medication Prescribed Date</FieldName>
            <Value>09/01/2013</Value>
          </MedicationProperty>
        </MedicationProperties>
      </UserMedication>
      <UserMedication>
        <MedicationProperties>
          <MedicationProperty CreatedDate="2013-11-14T16:41:12.783">
            <FieldName>Medication Name</FieldName>
            <Value>Celebrex</Value>
          </MedicationProperty>
          <MedicationProperty CreatedDate="2013-11-14T16:41:12.793">
            <FieldName>Medication Dosage</FieldName>
            <Value>50 mg twice a day</Value>
          </MedicationProperty>
          <MedicationProperty CreatedDate="2013-11-14T16:41:12.8">
            <FieldName>Medication Prescribed Date</FieldName>
            <Value>10/01/2013</Value>
          </MedicationProperty>
        </MedicationProperties>
      </UserMedication>
    </UserMedications>
    <UserProperties>
      <UserProperty CreatedDate="2013-12-03T13:48:03.45">
        <FieldName>User First Name</FieldName>
        <Value>John</Value>
      </UserProperty>
      <UserProperty CreatedDate="2013-12-03T11:36:31.423">
        <FieldName>User MI</FieldName>
        <Value>Q</Value>
      </UserProperty>
      <UserProperty CreatedDate="2013-11-19T09:56:44.66">
        <FieldName>User Last Name</FieldName>
        <Value>Public</Value>
      </UserProperty>
      <UserProperty CreatedDate="2013-11-14T16:41:12.803">
        <FieldName>User SSN</FieldName>
        <Value>111-22-3333</Value>
      </UserProperty>
    </UserProperties>
  </User>
</UserInformation>

Here are my objects:

public class EntityProperty
{
    [XmlIgnore]
    public int FieldId { get; set; }
    public string FieldName { get; set; }
    [XmlIgnore]
    public int FieldSortOrder { get; set; }
    [XmlAttribute()]
    public DateTime CreatedDate { get; set; }
    [XmlIgnore]
    public bool IsIterative { get; set; }
    public string Value { get; set; }
    public EntityTreeBase Entity { get; set; }
    public EntityProperty() { }
    public EntityProperty(int fieldId, string fieldName, int fieldSortOrder, DateTime createdDate, bool isIterative, string valueIn)
    {
        FieldId = fieldId;
        FieldName = FieldName;
        FieldSortOrder = fieldSortOrder;
        CreatedDate = createdDate;
        IsIterative = isIterative;
        Value = valueIn;
    }
}

public class EntityTreeBase
{
    [XmlIgnore]
    public long EntityId { get; set; }
    [XmlIgnore]
    public long? ParentEntityId { get; set; }
    [XmlIgnore]
    public int EntityDefinitionId { get; set; }
    [XmlIgnore]
    public int DestinationId { get; set; }
    [XmlIgnore]
    public int Level { get; set; }
    [XmlAttribute("EntityInfo")]
    public string EntityDefinitionName { get; set; }
    public EntityTreeBaseCollection Children { get; set; }
    public EntityPropertiesCollection Properties { get; set; }
    public EntityTreeBase() { }
    public EntityTreeBase(long entityId, long? parentEntityId, int entityDefinitionId, int destinationId, int level, string entityDefinitionName)
    {
        EntityId = entityId;
        ParentEntityId = parentEntityId;
        EntityDefinitionId = entityDefinitionId;
        DestinationId = destinationId;
        Level = level;
        EntityDefinitionName = entityDefinitionName;
    }
    public bool HasChildren
    {
        get { return (Children != null && Children.Count > 0); }
    }
    public bool HasProperties
    {
        get { return (Properties != null && Properties.Count > 0); }
    }
    public static EntityTreeBase BuildTree(EntityTreeBaseCollection collection, EntityTreeBase parent)
    {
        parent.Properties = EntityPropertiesCollection.GetProperties(parent.DestinationId, parent.EntityId, parent.EntityDefinitionId);
        parent.Children = new EntityTreeBaseCollection();
        foreach (EntityTreeBase item in EntityTreeBaseCollection.FindChildEntities(collection, parent.EntityId))
        {
            parent.Children.Add(BuildTree(EntityTreeBaseCollection.GetChildren(item.EntityId, item.Level, item.DestinationId), item));
        }
        if (!parent.HasChildren)
        {
            parent.Children = null;
        }
        if (!parent.HasProperties)
        {
            parent.Properties = null;
        }
        return parent;
    }
}

So, as is hopefully obvious, there are no object types named "Medication" or "User", these must be inferred from the data. So I need to know how to use values from the data to change my element names, but I need to figure out how to crawl the object tree so each element name is changed based on the associated EntityDefinitionName. I'm using recursion to populate my object tree prior to serialization. I know the following code works to rename my XmlRoot:

XmlAttributeOverrides xmlOverrides = new XmlAttributeOverrides();
XmlAttributes attribs = new XmlAttributes();
XmlRootAttribute rootAttr = new XmlRootAttribute();
rootAttr.ElementName = collection.Find(e => e.Level == 1).EntityDefinitionName.Replace(" ", "");
attribs.XmlRoot = rootAttr;

But I need to figure out how to change each element name based on the EntityDefinitionName associated with that element or node.

Thanks in advance!

Although I think you can achieve that by using custom serialization I want to present a different approach to solving your question by using an XSLT stylesheet.

This stylesheet transforms your input xml to your desired output xml:

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
                exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="ArrayOfEntityTreeBase">
       <UserInformation >
        <xsl:apply-templates />
       </UserInformation>
    </xsl:template>

  <xsl:template match="EntityTreeBase[@EntityInfo='User']">
    <User>
      <xsl:apply-templates />
    </User>
  </xsl:template>

  <xsl:template match="Children">
    <UserMedications>
      <xsl:apply-templates />
    </UserMedications>
  </xsl:template>

  <xsl:template match="EntityTreeBase[@EntityInfo='User Medication']">
    <UserMedication>
      <xsl:apply-templates />
    </UserMedication>
  </xsl:template>

  <xsl:template match="EntityTreeBase[@EntityInfo='User Medication']/Properties">
    <MedicationProperties>
      <xsl:apply-templates />
    </MedicationProperties>
  </xsl:template>

  <xsl:template match="EntityTreeBase[@EntityInfo='User']/Properties">
    <UserProperties>
      <xsl:apply-templates/>
    </UserProperties>
  </xsl:template>

  <xsl:template match="EntityTreeBase[@EntityInfo='User']/Properties/EntityProperty">
    <xsl:element name="UserProperty">
      <xsl:copy-of select="@*"/>
      <xsl:copy-of select="*" />
    </xsl:element>
  </xsl:template>

  <xsl:template match="EntityTreeBase[@EntityInfo='User Medication']/Properties/EntityProperty">
    <xsl:element name="MedicationProperty">
      <xsl:copy-of select="@*"/>
       <xsl:copy-of select="*" />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

This is the code that you can use the run the transformation in your c# code:

 var xml = File.Open("input.xml", FileMode.Open); // or any stream
 var xslTrans = new XslCompiledTransform();
 xslTrans.Load(XmlReader.Create(File.Open("yourxslfile.xlst", FileMode.Open)));
 var output = File.Create("output.xml");  // or a stream
 var xw = XmlWriter.Create(output);
 xslTrans.Transform(XmlReader.Create(xml), xw );
 xw.Close();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM