ここで何が間違っているのでしょうか、C#を使用したXSLTに問題があります
質問
この行でエラーが発生するため、次のコードを見てください。
xslt.Transform(mydoc.CreateReader(), writer);
エラー:
ステップイン:非ユーザーコードのステップ「System.xml.linq.xnode.createreader 'タイプの最初のチャンスの例外' System.nullreferenceException 'がSystem.data.sqlxml.dllで発生しました
((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)at system.xml.xsl.runtime.xmlquittut.starttut.tarttute(xpattepte。 runtime.xmlqueryoutput.writestartroot ()atrut(xmlqueryruntime {urn:schemas-microsoft-com:xslt-debug}実行時) (Object DefaultDocument、XmlResolver DataSources、XSLTargumentList ArgumentList、XMLWriter Writer、Boolean CloseWriter)at System.xml.xl.xmlilcommand.execute(xmlreder contextdocument、xmlresolver Datasours、x compiledtransform.transform( XMLReader入力、XSLTARGUMENTLIST引数、XMLWRITER結果)PROMO.PAGE_LOAD(Object Sender、EventArgs E)
これを実行すると機能します:
StringWriter sw = new StringWriter();
xslt.Transform(mydoc.CreateReader(),null, sw);
XmlWriter の何が間違っているのでしょうか?
クラッシュ直前の xdoc の値:
<Promotions>
<Promotion>
<Category>Arts & Entertainment</Category>
<Client>Client1</Client>
<Title>Get your Free 2</Title>
</Promotion>
<Promotion>
<Category>Arts & Entertainment</Category>
<Client>Client1</Client>
<Title>Get your Free 4</Title>
</Promotion>
<Promotion>
<Category>Arts & Entertainment</Category>
<Client>client1</Client>
<Title>Get your Free 5</Title>
</Promotion>
<Promotion>
<Category>Community & 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>
解決
問題は、LINQ to XML オブジェクト モデル (つまり、System.Xml.Linq.XDocument/XNode) には、フラグメントを表すクラスがありません。
XML 入力を受け取ると、コードは完璧に機能します (例:
<Promotions>
<Promotion>
<Category>Arts & Entertainment</Category>
<Client>Client1</Client>
<Title>Get your Free 2</Title>
</Promotion>
<Promotion>
<Category>Arts & Entertainment</Category>
<Client>Client1</Client>
<Title>Get your Free 4</Title>
</Promotion>
<Promotion>
<Category>Arts & Entertainment</Category>
<Client>client1</Client>
<Title>Get your Free 5</Title>
</Promotion>
<Promotion>
<Category>Community & 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>
) と 2 番目に投稿されたスタイルシート (例:
<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>
) 「EndRootElement 状態のトークン StartElement により無効な XML ドキュメントが生成される」という InvalidOperationException が発生します。XML フラグメントを書き込む場合は、ConformanceLevel 設定が ConformanceLevel.Fragment または ConformanceLevel.Auto に設定されていることを確認してください。」C# コードで行ったように、XmlWriter を ConformanceLevel.Fragment を使用して別の XmlWriter にラップすることでこれに対抗しようとしたのではないかと思いますが、それは機能せず、別の例外が発生するだけだと思います。
私の見解では、フラグメントを XElement に追加できるはずなので、XElement インスタンスで CreateWriter() を使用すると機能するはずです。ただし、私のテストでは依然として例外がスローされるため、それについてバグを報告しました。を参照してください。 https://connect.microsoft.com/VisualStudio/フィードバック/詳細/530052/xslt-stylesheet-writing-an-xml-fragment-to-an-xmlwriter-created-with-xelementinstance-createwriter-causes-nullreferenceException
他のヒント
<Category>
要素のリストではなく、完全なXMLドキュメントを含むXMLを生成しているように、に見えます。そして、あなたは空XDocument
にフラグメントを書き込むしようとしています。あなたは常にXML内の1つのルート要素を必要とするので、それは、無効な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>
あなたはmydoc
を定義しましたか?私はそれのnullを賭けます。
あなたのnew XDeclaration("2.0","utf-8","true")
コードでXML 2.0文書を作成することを意味していましたか?それが問題を引き起こしているかどうかは知りませんが、XML 2.0が存在しないので、それは、確かにやっている奇妙なことです。それを完全に削除してください。あなたがそれを必要はありません。
、このコードの実行が延期されてもよい。
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)));
あなたのエラーはおそらく、このコードで行われています。 XElementの作成を通じてステップに、あなたのLINQにブレークポイントを置いてみてください。それとも、あなたは以下の行うことができ、実行が延期されていないことを確認します。
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()
);