1

做这样的事情:

using (XmlWriter myMamlHelpWriter = XmlWriter.Create(myFileStream, XmlHelpExToMamlXslTransform.OutputSettings))
{
    XmlHelpExToMamlXslTransform.Transform(myMsHelpExTopicFilePath, null, myMamlHelpWriter);
}

在哪里

private static XslCompiledTransform XmlHelpExToMamlXslTransform
{
    get
    {
        if (fMsHelpExToMamlXslTransform == null)
        {
            // Create the XslCompiledTransform and load the stylesheet.
            fMsHelpExToMamlXslTransform = new XslCompiledTransform();
            using (Stream myStream = typeof(XmlHelpBuilder).Assembly.GetManifestResourceStream(
                typeof(XmlHelpBuilder),
                MamlXmlTopicConsts.cMsHelpExToMamlTransformationResourceName))
            {
                XmlTextReader myReader = new XmlTextReader(myStream);
                fMsHelpExToMamlXslTransform.Load(myReader, null, null);
            }
        }

        return fMsHelpExToMamlXslTransform;
    }
}

并且每次字符串 """ 替换为结果文件中的实引号。
无法理解为什么会发生这种情况......

4

3 回答 3

1

The XSLT processor doesn't know whether a character was represented by a character entity or not. This is because the XML parser substitutes any character entity with its code-value.

Therefore, the XSLT processor would see exactly the same character, regardless whether it was represented as " or as " or as " or as ".

What you want can be achieved in XSLT 2.0 by using the so called "character maps".

于 2013-01-25T18:07:05.507 回答
1

原因是在 XSLT 的内部表示中,"". 它们都代表 ascii 代码点 0x34。看起来,当 XslCompiledTransform 产生其输出时,它使用"了合法的地方。我想它仍然会"在属性值内输出。

在输出"中产生的问题对您来说是一个问题吗?"

我刚刚使用任意输入文件在 Visual Studio 中运行了以下 XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/*">
    <xml>
      <xsl:variable name="chars">&quot;&apos;&lt;&gt;&amp;</xsl:variable>
      <node a='{$chars}' b="{$chars}">
        <xsl:value-of select="$chars"/>
      </node>
    </xml>
  </xsl:template>
</xsl:stylesheet>

输出是:

<xml>
  <node a="&quot;'&lt;&gt;&amp;" b="&quot;'&lt;&gt;&amp;">"'&lt;&gt;&amp;</node>
</xml>

正如您所看到的,即使所有五个字符最初都表示为实体,但撇号的产生是'随处可见的,引号是"在文本节点中产生的。此外,a具有分隔符的属性在输出中'使用分隔符。"正如我所说,就 XSLT 而言,引号只是一个引号,一个属性只是一个属性。如何在输出中产生这些取决于 XSLT 处理器。

编辑:此行为的根本原因似乎是 XmlWriter 类的行为。对于那些想要更多自定义转义的人来说,一般建议是扩展XmlTextWriter类。 这个页面有一个看起来相当有前途的实现:

public class KeepEntityXmlTextWriter : XmlTextWriter
{
    private static readonly string[] ENTITY_SUBS = new string[] { "&apos;", "&quot;" };
    private static readonly char[] REPLACE_CHARS = new char[] { '\'', '"' };

    public KeepEntityXmlTextWriter(string filename) : base(filename, null) { ; }

    private void WriteStringWithReplace(string text)
    {
        string[] textSegments = text.Split(KeepEntityXmlTextWriter.REPLACE_CHARS);

        if (textSegments.Length > 1)
        {
            for (int pos = -1, i = 0; i < textSegments.Length; ++i)
            {
                base.WriteString(textSegments[i]);
                pos += textSegments[i].Length + 1;

                // Assertion: Replace the following if-else when the number of
                // replacement characters and substitute entities has grown
                // greater than 2.
                Debug.Assert(2 == KeepEntityXmlTextWriter.REPLACE_CHARS.Length);

                if (pos != text.Length)
                {
                    if (text[pos] == KeepEntityXmlTextWriter.REPLACE_CHARS[0])
                        base.WriteRaw(KeepEntityXmlTextWriter.ENTITY_SUBS[0]);
                    else
                        base.WriteRaw(KeepEntityXmlTextWriter.ENTITY_SUBS[1]);
                }
            }
        }
        else base.WriteString(text);
    }

    public override void WriteString( string text)
    {
        this.WriteStringWithReplace(text);
    }
}

另一方面,MSDN 文档建议使用XmlWriter.Create()而不是直接实例化 XmlTextWriters。

在 .NET Framework 2.0 版本中,推荐的做法是使用 XmlWriter.Create 方法和 XmlWriterSettings 类创建 XmlWriter 实例。这使您可以充分利用此版本中引入的所有新功能。有关更多信息,请参阅创建 XML 编写器。

解决这个问题的一种方法是使用与上面相同的逻辑,但将其放在一个包装XmlWriter. 此页面有一个现成的 XmlWrappingWriter 实现,您可以根据需要对其进行修改。

要将上面的代码与XmlWrappingWriter.

public class KeepEntityWrapper : XmlWrappingWriter
{
    public KeepEntityWrapper(XmlWriter baseWriter)
        : base(baseWriter)
    {
    }

    private static readonly string[] ENTITY_SUBS = new string[] { "&apos;", "&quot;" };
    private static readonly char[] REPLACE_CHARS = new char[] { '\'', '"' };

    private void WriteStringWithReplace(string text)
    {
        string[] textSegments = text.Split(REPLACE_CHARS);

        if (textSegments.Length > 1)
        {
            for (int pos = -1, i = 0; i < textSegments.Length; ++i)
            {
                base.WriteString(textSegments[i]);
                pos += textSegments[i].Length + 1;

                // Assertion: Replace the following if-else when the number of
                // replacement characters and substitute entities has grown
                // greater than 2.
                Debug.Assert(2 == REPLACE_CHARS.Length);

                if (pos != text.Length)
                {
                    if (text[pos] == REPLACE_CHARS[0])
                        base.WriteRaw(ENTITY_SUBS[0]);
                    else
                        base.WriteRaw(ENTITY_SUBS[1]);
                }
            }
        }
        else base.WriteString(text);
    }

    public override void WriteString(string text)
    {
        this.WriteStringWithReplace(text);
    }
}

请注意,这与 基本相同的代码KeepEntityXmlTextWriter,但使用 XmlWrappingWriter 作为基类并使用不同的构造函数。

我不知道Guard代码XmlWrappingWriter在两个地方使用,但鉴于您将自己使用代码,删除这样的行应该是非常安全的。他们只是确保不会将空值传递给构造函数或(在上述情况下不可访问)BaseWriter属性:

Guard.ArgumentNotNull(baseWriter, "baseWriter");

要创建 的实例XmlWrappingWriter,您可以根据需要创建一个 XmlWriter,然后使用:

KeepEntityWrapper wrap = new KeepEntityWrapper(writer);

然后您将使用此wrap变量作为您传递给 XSL 转换的 XmlWriter。

于 2013-01-25T18:00:12.547 回答
1

这是您想要的技巧:

  1. 全部替换&&amp;
  2. 执行 XSLT
  3. 全部替换&amp;&
于 2017-03-23T14:47:43.263 回答