Traversing an arbitrary C# object graph using XPath/applying XSL transforms

后端 未结 4 483
孤独总比滥情好
孤独总比滥情好 2021-01-04 09:21

I\'ve been looking for a component that would allow me to pass an arbitrary C# object to an XSL transform.

The naive way of doing this is to serialise the object gra

相关标签:
4条回答
  • 2021-01-04 09:41

    Since the object graph may be cyclic, you cannot possibly make a Tree-based structure out of it. Your best bet is to represent the object graph by it's simplest components: nodes and vectors.

    More specifically, make each node (object) an element with a unique ID (perhaps provided by C#'s GetHashCode() method?). References to other objects (vectors) would be handled by referencing the ID of the object.

    Example classes (note that I don't know C# so my syntax may be a bit off):

    public class SomeType {
       public int myInt  { get; set; }
    }
    
    public class AnotherType {
       public string myString { get; set; }
       public SomeType mySomeType { get; set; }
    }
    
    public class LastType {
       public SomeType mySomeType { get; set; }
       public AnotherType myAnotherType { get; set; }
    }
    
    public class UserTypes{
        static void Main()
        {
            LastType lt = new LastType();
            SomeType st = new SomeType();
            AnotherType atype = new AnotherType();
    
            st.myInt = 7;
            atype.myString = "BOB";
            atype.mySomeType = st;
            lt.mySomeType = st;
            lt.myAnotherType = atype;
    
            string xmlOutput = YourAwesomeFunction(lt);
        }
    }
    

    Then we would expect the value of xmlOutput to be something like this (note that the ID values chosen are completely synthetic):

    <ObjectMap>
     <LastType id="0">
       <mySomeType idref="1" />
       <myAnotherType idref="2" />
     </LastType>
    
     <SomeType id="1">
      <myInt>7</myInt>
     </SomeType>
    
     <AnotherType id="2">
      <myString>BOB</myString>
      <mySomeType idref="1" />
     </AnotherType>
    </ObjectMap>
    
    0 讨论(0)
  • 2021-01-04 09:44

    You could try something like this:

    http://code.google.com/p/antix-software/wiki/AntixReflectionQuery

    0 讨论(0)
  • 2021-01-04 09:46

    Sounds as though the problem you're trying to solve is quite interesting.

    At first glance, I'd suggest writing your own implementation of an XPathNavigator descendant - there are only 20-odd methods to write, and none of them have a particularly difficult signature.

    A naive implementation using non-cached reflection would be slow(ish) but would work well as a proof of concept and you could make changes to improve performance if/when that became an issue.

    However ...

    ... I think you may run into some difficulties that stem from your approach, not from any implementation detail.

    An XML file is (by nature) a simple hierarchy of elements and attributes - there are no loops (aka cycles) in the node graph.

    An XPath expression can include the operator "//" which broadly means to search to unlimited depth. (For an exact definition, see section 2.5 of XPath 1.0.)

    If you applied such an expression to an object graph with cross references (aka object cycles), then you run the risk of the XPath evaluator going into an infinite loop as it tried to recursively enumerate an effectively infinite graph.

    You may be able to work around this issue by somehow keeping track of parent nodes in your XPathNavigator and throwing an exception if a loop is detected, but I'm not sure how viable this will be.

    0 讨论(0)
  • 2021-01-04 10:00

    There's a (very) old MSDN article titled XPath Querying Over Objects with ObjectXPathNavigator that implements a similar class (Also called ObjectXPathNavigator, interestingly enough). I used this ages ago to query some data from Visual SourceSafe and build an RSS feed from the changelog, and it worked quite well. However, I didn't do XSLT with it, so I'm not sure if that works or not. Also, note that it was written for Framework 1.0, so you may need to update it for more recent frameoworks. Also, there may be better ways to do this now, but it would give you a starting point (and the article does a nice job of explaining how it works).

    0 讨论(0)
提交回复
热议问题