2

请看下面的代码,因为我在这一行得到错误:

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

错误:

步入:跨过非用户代码“System.Xml.Linq.XNode.CreateReader” System.Data.SqlXml.dll 中发生“System.NullReferenceException”类型的第一次机会异常

((System.NullReferenceException)(ex))

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}runtime) 在 Execute(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}runtime) 在 System.Xml.Xsl.XmlILCommand.Execute System.Xml.Xsl.XmlILCommand.Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter results) 在 System.Xml.Xsl 的(对象 defaultDocument、XmlResolver dataSources、XsltArgumentList argumentList、XmlWriter writer、Boolean closeWriter)。

现在,如果我这样做,它会起作用:

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

5 回答 5

2

看起来您的 XSLT 正在生成一个包含元素列表的 XML片段<Category>,而不是一个完整的 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>
于 2010-02-02T03:34:28.673 回答
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 状态的令牌 StartElement 会导致无效的 XML 文档。如果要编写 XML 片段,请确保 ConformanceLevel 设置设置为 ConformanceLevel.Fragment 或 ConformanceLevel.Auto。”。我怀疑您试图通过使用 ConformanceLevel.Fragment 将 XmlWriter 包装到另一个 XmlWriter 中来解决这个问题,就像您在 C# 代码中所做的那样,但我认为这不起作用,它只会导致不同的异常。

在我看来,应该在 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

于 2010-02-02T14:09:16.707 回答
0

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

于 2010-02-02T02:06:52.933 回答
0

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

于 2010-02-02T02:28:13.147 回答
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()
);
于 2010-02-02T02:54:47.703 回答