首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >XslCompiledTransform忽略.NET Framework4.6及以上版本上的DTD模式

XslCompiledTransform忽略.NET Framework4.6及以上版本上的DTD模式
EN

Stack Overflow用户
提问于 2020-03-19 18:32:05
回答 1查看 247关注 0票数 0

目标是通过运行XSL转换,用DTD中指定的键(短的和完整的/ref标记名)交换XML标记:

XSL确定XML的格式是:

  • XSL试图为DTD
  • 中的XML标记查找相反的键(缩写为full,full )。

所以XML

代码语言:javascript
复制
<!DOCTYPE Note SYSTEM "note.dtd">
<Note>
    <To>Tove</To>
    <From>Jani</From>
    <Heading>Reminder</Heading>
    <Body>Don't forget me this weekend</Body>
</Note>

变成了

代码语言:javascript
复制
<note>
    <x1>Tove</x1>
    <x2>Jani<x2/>
    <x3>Reminder</x3>
    <x4>Don't forget me this weekend</x4>
<note>

对于此任务,使用了以下DTD (只指定了一个替换以保持其代表性)

代码语言:javascript
复制
<!ELEMENT Note (To,From,Heading,Body)>
<!ELEMENT To (#PCDATA)>
<!ATTLIST To
  refname (To) #FIXED "To"
  shortname (to) #FIXED "x1">
<!ELEMENT From (#PCDATA)>
<!ELEMENT Heading (#PCDATA)>
<!ELEMENT Body (#PCDATA)>

正在运行以下XSL

代码语言:javascript
复制
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
  <xsl:variable name="target">
    <xsl:choose>
      <xsl:when test="local-name(/*)='Note'">short</xsl:when>
      <xsl:otherwise>reference</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:template match="*">
    <xsl:variable name="target-name">
      <xsl:choose>
        <xsl:when test="($target='short') and not(@shortname)">
          <xsl:value-of select="name()"/>
        </xsl:when>
        <xsl:when test="$target='short'">
          <xsl:value-of select="@shortname"/>
        </xsl:when>
        <xsl:when test="not(@refname)">
          <xsl:value-of select="name()"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@refname"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:element name="{$target-name}">
      <xsl:copy-of select="@*[not(name()='refname' or name()='shortname')]"/>
      <xsl:apply-templates select="*|text()"/>
    </xsl:element>
  </xsl:template>
  <xsl:template match="text()">
    <xsl:copy/>
  </xsl:template>
</xsl:stylesheet>

它在.NET Framework4.5(或MSBuild 14)中工作得很好,而且更低,但是一旦代码运行在更高的版本上,那么替换就不会发生了!在这个问题上花了几个小时之后,我可以说DTD在更高版本中完全被忽略了:我故意将一个错误的DTP路径放置到XML顶部:

An error has occurred while opening external DTD 'file:///.../1note.dtd': Could not find file 'C:\...\1note.dtd'.

  • .NET

  • .NET Framework4.5和较低的预期错误:Framework4.6和更高版本-没有转换,则返回输入的XML。

我编写了下面的C#代码来演示这个

代码语言:javascript
复制
using System;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Xsl;

using Xunit;

public class Tests
{
    private const string DtdDirectoryPath = @"c:\source\...\Resources";
    private const string DtdFileName = "note.dtd";

    private const string RootTag = "Note";
    private string xml = @"
<Note>
  <To>Tove</To>
  <From>Jani</From>
  <Heading>Reminder</Heading>
  <Body>Don't forget me this weekend</Body>
</Note>";

    [Fact]
    public void Test()
    {
        // copy the DTD to the expected location
        var dtdFilePath = Path.Combine(Environment.CurrentDirectory, DtdFileName);
        File.Copy(Path.Combine(DtdDirectoryPath, DtdFileName), dtdFilePath, overwrite: true);

        XslCompiledTransform xslt;
        using (var stringReader = new StringReader(Resources.SwitchTagNamesXSL))
        using (var xmlReader = new XmlTextReader(stringReader))
        {
            xslt = new XslCompiledTransform(enableDebug: true);
            xslt.Load(xmlReader);
        }

        // add the DTD definition at the XML top in order the XSL transformation pass
        this.xml = this.xml.Insert(
            0,
            new XDocumentType(RootTag, publicId: null, systemId: DtdFileName, internalSubset: null).ToString());

        Console.WriteLine("Initial XML with DTD at the top");
        Console.WriteLine(this.xml);

        var output = new XDocument();
        using (var writer = output.CreateWriter())
        using (var stringReader = new StringReader(this.xml))
        using (var reader = XmlReader.Create(
            stringReader,
            new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse })) // this flag is important to force DTD Processing
        {
            xslt.Transform(reader, writer);
        }

        Console.WriteLine("Output");
        Console.WriteLine(output);
    }
}

看来这个特性在最新的.NET框架中丢失了,作为解决办法,我一直在考虑编写自定义代码

  • 或XSL中的脚本或
  • 在C#

中执行转换

不过,我希望有人能知道一些关于这种不端行为的事情。

在我低估DTD被完全忽略之前,我花了很多时间搜索这个问题,做了很多实验,但这些实验都没有发生:

XslCompiledTransform

  • set

  • 不同的测试框架: XUnin、NUnit

  • 运行在不同的机器上,

  • x64 x86

  • 中启用了脚本,为XslCompiledTransform

设置了不同的设置

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-03-19 20:09:15

我认为您的XmlReaderSettings需要显式地定义一个XmlResolver

代码语言:javascript
复制
new XmlReaderSettings() { DtdProcessing = DtdProcessing.Parse, XmlResolver = new XmlUrlResolver() }

请参阅https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmlreadersettings.xmlresolver?view=netframework-4.8

默认值是一个没有凭据的新XmlUrlResolver。从.NET框架4.5.2开始,此设置的默认值为null.

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60763152

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档