【问题标题】:Transforming XML as a string with XSLT as a string in C# .NET 4.0 - Invalid characters in path在 C# .NET 4.0 中使用 XSLT 作为字符串将 XML 转换为字符串 - 路径中的字符无效
【发布时间】:2012-10-30 15:34:15
【问题描述】:

我有一个 XML 文件定义为:

<?xml version="1.0" encoding='UTF-8'?>
<contentlets>
<content>
  <entry>
    <string>link</string>
    <string>http://www.myLink.com</string>
  </entry>
  <entry>
    <string>stInode</string>
    <string>0b4f59c1-6dee-4c1e-a0fb-353c34c8d372</string>
  </entry>
  <entry>
    <string>linkType</string>
    <string>Category Title</string>
  </entry>
  <entry>
    <string>linkText</string>
    <string>Title</string>
  </entry>
</content>
</contentlets>

和一个 XSLT 定义为:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="html" omit-xml-declaration="yes" indent="yes"/>
    <xsl:template match="@* | node()">
        <div id="content" data-role="content">
            <ul data-role="listview" data-inset="true" data-filter="false">
                <li data-role="list-divider">Category Title</li>
                <xsl:for-each select="content">
                    <li data-inline="false" data-icon="arrow-r" data-iconpos="right">
                        <a target="_blank">
                        <xsl:for-each select="entry">
                            <xsl:if test="string='link'">
                                <xsl:attribute name="href">
                                    <xsl:value-of select="string[2]"/>
                                </xsl:attribute>
                            </xsl:if>
                            <xsl:if test="string='linkText'">
                                <h3>
                                    <xsl:value-of select="string[2]"/>
                                </h3>
                            </xsl:if>
                        </xsl:for-each>
                        </a>
                    </li>
                </xsl:for-each>
            </ul>
        </div>
    </xsl:template>
</xsl:stylesheet>

我在 Visual Studio 2010 中成功应用了此转换,但是,我想应用此转换并将生成的 HTML 存储在字符串中。我正在使用定义如下的自定义类来执行此操作:

public class XsltTransformer
{
    private readonly XslCompiledTransform xslTransform;

    public XsltTransformer(string xsl)
    {
        try
        {
            xslTransform = new XslCompiledTransform();

            using (var stringReader = new StringReader(xsl))
            {
                using (var xslt = XmlReader.Create(stringReader))
                {
                    xslTransform.Load(xslt);
                }
            }
        }
        catch (Exception ex)
        {
            Log.WriteLine(ex.ToString());
        }
    }

    public string Transform(string strXml)
    {
        try
        {
            string output = String.Empty;
            using (StringReader sri = new StringReader(strXml))
            {
                using (XmlReader xri = XmlReader.Create(sri))
                {
                    using (StringWriter sw = new StringWriter())
                    using (XmlWriter xwo = XmlWriter.Create(sw, xslTransform.OutputSettings))
                    {
                        xslTransform.Transform(xri, xwo);
                        output = sw.ToString();
                    }
                }
            }

            return output;
        }
        catch (Exception ex)
        {
            Log.WriteLine(ex.ToString());
            return String.Empty;
        }
    }
}

然后我调用以下命令来实际应用转换:

string strXslt = String.Empty;
string strXml = String.Empty;

using (StreamReader xsltReader = new StreamReader(Server.MapPath("~/Content/xsl/test.xslt")))
{
    strXslt = xsltReader.ReadToEnd();
}

using (StreamReader xmlReader = new StreamReader(Server.MapPath("~/Content/xml/test.xml")))
{
    strXml = xmlReader.ReadToEnd();
}

XsltTransformer transformer = new XsltTransformer(strXslt);
return transformer.Transform(strXml);

应用转换时,我收到“路径中的非法字符”。错误。我知道我的 XML 和 XSLT 文件以字符串的形式正确通过,但我无法弄清楚为什么在应用转换时会出现此错误。

关于是什么导致此错误的任何想法?

编辑: 这是堆栈跟踪:

[ArgumentException: Illegal characters in path.]
System.IO.Path.CheckInvalidPathChars(String path) +126
System.IO.Path.Combine(String path1, String path2) +38
System.Web.Compilation.DiskBuildResultCache.GetPreservedDataFileName(String cacheKey) +27
System.Web.Compilation.DiskBuildResultCache.GetBuildResult(String cacheKey, VirtualPath virtualPath, Int64 hashCode, Boolean ensureIsUpToDate) +14
System.Web.Compilation.BuildManager.GetBuildResultFromCacheInternal(String cacheKey, Boolean keyFromVPP, VirtualPath virtualPath, Int64 hashCode, Boolean ensureIsUpToDate) +200
System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath, Boolean ensureIsUpToDate) +51
System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) +68
System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) +111
System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound) +125
System.Web.Compilation.BuildManager.GetObjectFactory(String virtualPath, Boolean throwIfNotFound) +35
System.Web.Mvc.BuildManagerWrapper.System.Web.Mvc.IBuildManager.FileExists(String virtualPath) +9
System.Web.Mvc.BuildManagerViewEngine.FileExists(ControllerContext controllerContext, String virtualPath) +41
System.Web.Mvc.VirtualPathProviderViewEngine.GetPathFromGeneralName(ControllerContext controllerContext, List`1 locations, String name, String controllerName, String areaName, String cacheKey, String[]& searchedLocations) +150
System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations) +304
System.Web.Mvc.VirtualPathProviderViewEngine.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache) +136
System.Web.Mvc.<>c__DisplayClassc.<FindView>b__b(IViewEngine e) +24
System.Web.Mvc.ViewEngineCollection.Find(Func`2 lookup, Boolean trackSearchedPaths) +127
System.Web.Mvc.ViewEngineCollection.FindView(ControllerContext controllerContext, String viewName, String masterName) +181
System.Web.Mvc.ViewResult.FindView(ControllerContext context) +138
System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +129
System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +13
System.Web.Mvc.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19() +23
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +260
System.Web.Mvc.<>c__DisplayClass1e.<InvokeActionResultWithFilters>b__1b() +19
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +177
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
System.Web.Mvc.Controller.ExecuteCore() +116
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8836913
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184

【问题讨论】:

  • 考虑发布异常发生时得到的堆栈跟踪。
  • XslCompiledTransform 方法和您的 XsltTransformer 方法(如 Transform)都不会出现在堆栈跟踪中,因此看起来异常与您发布的 XSLT 特定代码无关。
  • 我不能重复(在 ASP.NET MVC 4 中) - 我假设 return transformer.Transform(strXml); 从具有字符串返回类型的控制器方法返回。这将返回转换后的 HTML,IE 可以完美呈现。可能检查 .xslt 和 .xml 文件上的实际编码是否与规定的编码 (utf-8) 匹配,如果文件名中有任何可转义的字符(如果它们未经过测试),请在文件路径前加上“@”前缀.xml / test.xslt.
  • 这是一个 ArgumentException,所以对于某些对象的 ctor,而不是传递 文件路径,你传递的是 xml 字符串
  • @Mark:XslCompiledTransform 的 Transform 方法采用 XmlReader 和 XmlWriter 类型的参数,而不是任何字符串。据我所知,这是 Transform 方法的正确使用。

标签: xml asp.net-mvc c#-4.0 xslt


【解决方案1】:

替换:

<a target="_blank">
    <xsl:for-each select="entry">
        <xsl:if test="string='link'">
            <xsl:attribute name="href">
                <xsl:value-of select="string[2]"/>
            </xsl:attribute>
        </xsl:if>
        <xsl:if test="string='linkText'">
            <h3>
                <xsl:value-of select="string[2]"/>
            </h3>
        </xsl:if>
    </xsl:for-each>
</a>

与:

<xsl:element name="a">
    <xsl:attribute name="target">
        <xsl:text>_blank</xsl:text>
    </xsl:attribute>
    <xsl:if test="./entry/string[1]/text()[.='link']">
        <xsl:attribute name="href">
            <xsl:value-of select="(./entry[./string[1]/text()='link']/string[2]/text())[1]"/>
        </xsl:attribute>
    </xsl:if>
    <xsl:if test="./entry/string[1]/text()[.='linkText']">
        <xsl:element name="h3">
            <xsl:value-of select="(./entry[./string[1]/text()='linkText']/string[2]/text())[1]"/>
        </xsl:element>
    </xsl:if>
</xsl:element>

ps。我也会改变

using (StringWriter sw = new StringWriter())
using (XmlWriter xwo = XmlWriter.Create(sw, xslTransform.OutputSettings))
{
    xslTransform.Transform(xri, xwo);
    output = sw.ToString();
}

using (StringWriter sw = new StringWriter())
{
    using (XmlWriter xwo = XmlWriter.Create(sw, xslTransform.OutputSettings))
    {
        xslTransform.Transform(xri, xwo);
    }
    output = sw.ToString();
}

【讨论】:

  • 我仍然收到相同的“路径中的非法字符”。错误。我唯一可以让转换工作的情况是,如果我调用xslTransform.Transform() 以便将其输出到文件中。每当我调用 Transform() 以便将转换输出到某种 Stream 时,就会出现此错误。任何其他想法为什么这在输出到文件而不是流时有效?
  • 猜测 - 尝试检查文件编码是否与 XML 声明的编码(即 UTF-8)匹配,如果这不是问题,请在读入/推出数据时指定编码。还要在输出 XML 中添加一个 xml 声明,以确保在那里也指定了编码。我会敲出代码让你测试这个理论,但遗憾的是直到周末才有机会。 . .
  • 我已经确认 XML 和 XSLT 文件都以 UTF-8 编码,并将数据读入 StreamReaderSystem.Text.UTF8Encoding()。我还尝试使用不同的输出设置进行转换,以使用和不使用 XML 声明以 HTML 或 XML 输出。仍然收到“路径中的非法字符”错误。感谢您的帮助,还有其他想法吗?
  • 只需重新阅读您的问题 / 使用堆栈跟踪 - 堆栈跟踪不是来自转换代码 - 它也不完整;那里的所有内容都引用系统库-我希望其中至少有一行引用您的代码?您提到在应用转换时遇到错误 - 您的意思是抛出错误的行是该行,还是您的意思是在某些时候抛出错误但仅在包含转换行时?
  • 我真的不知道错误是在哪里引发的,即使使用 try/catch 也没有在我的代码中被捕获。但是,当我注释掉 xslTransform.Transform(xri, xwo) 时,不再抛出错误。所以是的,错误是在某个时候抛出的,但只有在包含转换线时才会抛出。
猜你喜欢
  • 1970-01-01
  • 2014-01-03
  • 2010-12-15
  • 1970-01-01
  • 2012-10-26
  • 1970-01-01
  • 2017-11-10
  • 1970-01-01
  • 2021-09-23
相关资源
最近更新 更多