我在这里做错了什么,使用C#解决XSLT问题

时间:2010-02-02 02:02:27

标签: c# xslt xmlwriter

请查看以下代码,因为我在此行收到错误:

xslt.Transform(mydoc.CreateReader(), writer);

错误:

单步执行:单步执行非用户代码'System.Xml.Linq.XNode.CreateReader' System.Data.SqlXml.dll中发生了'System.NullReferenceException'类型的第一次机会异常

((System.NullReferenceException)(前))

PromotionsDataContext db = new PromotionsDataContext();
//XmlDocument myxml;

XElement Categories =
    new XElement("Promotions",
        from b in db.GetPromotions()
        select new XElement("Promotion",
            new XElement("Category", b.CategoryName),
               new XElement("Client", b.ClientName),
               new XElement("Title", b.Title)));



XDocument mydoc = new XDocument();
mydoc.Add(Categories);


try
{

    XDocument newTree = new XDocument();


    XmlWriterSettings settings = new XmlWriterSettings();
    settings.OmitXmlDeclaration = true;
    settings.ConformanceLevel = ConformanceLevel.Fragment;
    settings.CloseOutput = false;

    //using (XmlWriter writer = newTree.CreateWriter())
    using (XmlWriter writer = XmlWriter.Create(newTree.CreateWriter(), settings))
    {

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


        xslt.Load(XmlReader.Create(new FileStream(@"C:\1\TransList.xslt", System.IO.FileMode.Open)));

        // Execute the transform and output the results to a writer.

        xslt.Transform(mydoc.CreateReader(), writer);
    }

    Console.WriteLine(newTree);
}
catch (Exception ex)
{
    Console.Write(ex);

}

这是XSLT:

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  <xsl:output method='xml' />
  <xsl:key name='categories' match='Category' use='.' />
  <xsl:template match='/'>
    <xsl:for-each select="/Promotions/Promotion/Category[ 
        generate-id(.) = generate-id(key('categories', .)[1]) 
      ]">
      <xsl:variable name='cname' select='.' />
      <Category title='{.}'>
        <xsl:for-each select='/Promotions/Promotion[Category=$cname]'>
          <Title>
            <xsl:value-of select='Title' />
          </Title>
        </xsl:for-each>
      </Category>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

错误:

System.NullReferenceException:未将对象引用设置为对象的实例。    在System.Xml.Xsl.Runtime.XmlMergeSequenceWriter.StartTree(XPathNodeType rootType,IXmlNamespaceResolver nsResolver,XmlNameTable nameTable)    在System.Xml.Xsl.Runtime.XmlQueryOutput.StartTree(XPathNodeType rootType)    在System.Xml.Xsl.Runtime.XmlQueryOutput.WriteStartRoot()    在Root(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}运行时)    at Execute(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug} runtime)    在System.Xml.Xsl.XmlILCommand.Execute(Object defaultDocument,XmlResolver dataSources,XsltArgumentList argumentList,XmlWriter writer,Boolean closeWriter)    在System.Xml.Xsl.XmlILCommand.Execute(XmlReader contextDocument,XmlResolver dataSources,XsltArgumentList argumentList,XmlWriter结果)    在System.Xml.Xsl.XslCompiledTransform.Transform(XmlReader输入,XsltArgumentList参数,XmlWriter结果)    at Promo.Page_Load(Object sender,EventArgs e)在c:\ 1 \ promo.ascx.cs:第144行

现在,如果我这样做,它可以工作:

StringWriter sw = new StringWriter(); 
xslt.Transform(mydoc.CreateReader(),null, sw);

我在使用XmlWriter时遇到了什么问题?

崩溃前xdoc的值:

<Promotions>
  <Promotion>
    <Category>Arts &amp; Entertainment</Category>
    <Client>Client1</Client>
    <Title>Get your Free 2</Title>
  </Promotion>
  <Promotion>
    <Category>Arts &amp; Entertainment</Category>
    <Client>Client1</Client>
    <Title>Get your Free 4</Title>
  </Promotion>
  <Promotion>
    <Category>Arts &amp; Entertainment</Category>
    <Client>client1</Client>
    <Title>Get your Free 5</Title>
  </Promotion>
  <Promotion>
    <Category>Community &amp; Neighborhood</Category>
    <Client>Client2</Client>
    <Title>Get your Free 1</Title>
  </Promotion>
  <Promotion>
    <Category>Education</Category>
    <Client>Client3</Client>
    <Title>Get Your Free 3</Title>
  </Promotion>
</Promotions>

5 个答案:

答案 0 :(得分:2)

看起来您的XSLT正在生成包含<Category>元素列表的XML 片段,而不是完整的XML文档。而且您正在尝试将片段写入空XDocument。这将导致XML文档无效,因为您始终需要XML中的一个根元素。我不知道是否具体是导致您的异常的原因,但您应该看到当您修改XSLT时会发生什么:

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  <xsl:output method='xml' />
  <xsl:key name='categories' match='Category' use='.' />
  <xsl:template match='/'>
    <Categories> <!-- Added a root element here -->
        <xsl:for-each select="/Promotions/Promotion/Category[ 
            generate-id(.) = generate-id(key('categories', .)[1]) 
          ]">
          <xsl:variable name='cname' select='.' />
          <Category title='{.}'>
            <xsl:for-each select='/Promotions/Promotion[Category=$cname]'>
              <Title>
                <xsl:value-of select='Title' />
              </Title>
            </xsl:for-each>
          </Category>
        </xsl:for-each>
    </Categories>
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:2)

我认为问题确实是您似乎想要使用样式表和XmlWriter创建XML片段,而LINQ to XML对象模型(即System.Xml.Linq.XDocument / XNode)没有任何类表示片段。

如果我接受你的XML输入(例如

),代码可以完美地运行
<Promotions>
  <Promotion>
    <Category>Arts &amp; Entertainment</Category>
    <Client>Client1</Client>
    <Title>Get your Free 2</Title>
  </Promotion>
  <Promotion>
    <Category>Arts &amp; Entertainment</Category>
    <Client>Client1</Client>
    <Title>Get your Free 4</Title>
  </Promotion>
  <Promotion>
    <Category>Arts &amp; Entertainment</Category>
    <Client>client1</Client>
    <Title>Get your Free 5</Title>
  </Promotion>
  <Promotion>
    <Category>Community &amp; Neighborhood</Category>
    <Client>Client2</Client>
    <Title>Get your Free 1</Title>
  </Promotion>
  <Promotion>
    <Category>Education</Category>
    <Client>Client3</Client>
    <Title>Get Your Free 3</Title>
  </Promotion>
</Promotions>

)和第二个样式表(例如

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  <xsl:output method='xml' />
  <xsl:key name='categories' match='Category' use='.' />
  <xsl:template match='/'>
    <Categories>
      <!-- Added a root element here -->
      <xsl:for-each select="/Promotions/Promotion/Category[ 
            generate-id(.) = generate-id(key('categories', .)[1]) 
          ]">
        <xsl:variable name='cname' select='.' />
        <Category title='{.}'>
          <xsl:for-each select='/Promotions/Promotion[Category=$cname]'>
            <Title>
              <xsl:value-of select='Title' />
            </Title>
          </xsl:for-each>
        </Category>
      </xsl:for-each>
    </Categories>
  </xsl:template>
</xsl:stylesheet>

)然后使用以下C#代码:

    XDocument mydoc = XDocument.Load(@"..\..\XMLFile1.xml");

    XDocument newTree = new XDocument();

    using (XmlWriter writer = newTree.CreateWriter())
    {
        XslCompiledTransform xslt = new XslCompiledTransform();

        xslt.Load(@"..\..\XSLTFile2.xslt");

        xslt.Transform(mydoc.CreateReader(), writer);
        writer.Close();
    }

    Console.WriteLine(newTree);

当我使用原始样式表时(例如

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  <xsl:output method='xml' />
  <xsl:key name='categories' match='Category' use='.' />
  <xsl:template match='/'>
    <xsl:for-each select="/Promotions/Promotion/Category[ 
        generate-id(.) = generate-id(key('categories', .)[1]) 
      ]">
      <xsl:variable name='cname' select='.' />
      <Category title='{.}'>
        <xsl:for-each select='/Promotions/Promotion[Category=$cname]'>
          <Title>
            <xsl:value-of select='Title' />
          </Title>
        </xsl:for-each>
      </Category>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

)我得到一个InvalidOperationException,说“状态EndRootElement中的Token StartElement会导致无效的XML文档。如果要编写XML片段,请确保将ConformanceLevel设置设置为ConformanceLevel.Fragment或ConformanceLevel.Auto。”我怀疑你试图用你的C#代码将你的XmlWriter包装到另一个包含ConformanceLevel.Fragment的方法来解决这个问题,但是我认为这不起作用,它只会导致一个不同的异常。

我认为应该在XElement实例上使用CreateWriter(),因为应该可以将片段添加到XElement。然而,我的测试仍然会引发异常,因此我已经提交了一个错误,请参阅https://connect.microsoft.com/VisualStudio/feedback/details/530052/xslt-stylesheet-writing-an-xml-fragment-to-an-xmlwriter-created-with-xelementinstance-createwriter-causes-nullreferenceexception

答案 2 :(得分:0)

您在哪里定义mydoc?我打赌它是空的。

答案 3 :(得分:0)

您的意思是在new XDeclaration("2.0","utf-8","true")代码中创建XML 2.0文档吗?我不知道是否会导致这个问题,但这确实很奇怪,因为XML 2.0不存在。尝试完全删除它;你不应该需要它。

答案 4 :(得分:0)

因为XML是通过LINQ to XML构建的,所以可以推迟执行此代码:

XElement Categories = new XElement(
    "Promotions",
    from b in db.GetPromotions()
    select new XElement("Promotion",
        new XElement("Category", b.CategoryName),
           new XElement("Client", b.ClientName),
           new XElement("Title", b.Title)));

您的错误可能发生在此代码中。尝试在LINQ中放置断点以逐步完成XElement创建。或者,为了确保不延迟执行,您可以执行以下操作:

XElement Categories = new XElement(
    "Promotions",
    (
        from b in db.GetPromotions()
        select new XElement("Promotion",
            new XElement("Category", b.CategoryName),
            new XElement("Client", b.ClientName),
            new XElement("Title", b.Title))
    ).ToList()
);