使用XPath /应用XSL转换遍历任意C#对象图

时间:2008-12-16 16:20:45

标签: c# .net xml xpath xslt

我一直在寻找一个允许我将任意C#对象传递给XSL转换的组件。

这种天真的方法是使用XmlSerializer序列化对象图;但是,如果您有一个大型对象图,就性能而言,这可能会导致问题。诸如循环引用,延迟加载,代理等问题可能会使这里的水域更加混乱。

更好的方法是使用某种实现IXPathNavigable和XPathNavigator的Adapter类。我遇到的一个这样的例子是ObjectXPathNavigator from Byte-Force - 然而,它的大部分关键文档都是俄语的,我的初步测试似乎表明它有一些怪癖和特质。

是否有人知道(a)英语中有关此特定内容的任何资源(概述,教程,博客文章等)或(b)提供相同或类似功能的任何其他替代方案?< / p>

4 个答案:

答案 0 :(得分:6)

有一篇(非常)旧的MSDN文章标题为XPath Querying Over Objects with ObjectXPathNavigator ,它实现了一个类似的类(也称为ObjectXPathNavigator,有趣的是)。我在很久以前就用它来查询Visual SourceSafe中的一些数据,并从更改日志中构建一个RSS提要,它运行得很好。但是,我没有用它做XSLT,所以我不确定它是否有效。另请注意,它是为Framework 1.0编写的,因此您可能需要为更新的frameoworks更新它。此外,现在可能有更好的方法可以做到这一点,但它会给你一个起点(而且这篇文章很好地解释了它是如何工作的。)

答案 1 :(得分:2)

听起来你正试图解决的问题非常有趣。

乍一看,我建议编写自己的XPathNavigator后代实现 - 只有20多种方法可以编写,而且没有一种方法特别难以签名。

使用非缓存反射的简单实现会很慢(ish)但是作为概念证明可以很好地工作,如果/当这成为问题时,您可以进行更改以提高性能。

然而......

......我认为您可能遇到一些源于您的方法的困难,而不是任何实施细节。

XML文件(本质上)是元素和属性的简单层次结构 - 节点图中没有循环(也称为循环)。

XPath表达式可以包含运算符“//”,这意味着搜索到无限深度。 (有关确切的定义,请参阅XPath 1.0的第2.5节。)

如果将这样的表达式应用于具有交叉引用(也称为对象循环)的对象图,那么您将冒着XPath求值程序进入无限循环的风险,因为它试图递归枚举有效的无限图。

您可以通过某种方式跟踪XPathNavigator中的父节点并在检测到循环时抛出异常来解决此问题,但我不确定这将是多么可行。

答案 2 :(得分:0)

由于对象图可能是循环的,因此您不可能从中创建基于树的结构。最好的办法是用最简单的组件来表示对象图:节点和向量。

更具体地说,使每个节点(对象)成为具有唯一ID的元素(可能由C#的GetHashCode()方法提供?)。可以通过引用对象的ID来处理对其他对象(向量)的引用。

示例类(注意我不知道C#所以我的语法可能有点偏离):

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);
    }
}

然后我们希望xmlOutput的值是这样的(请注意,所选的ID值是完全合成的):

<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>

答案 3 :(得分:0)