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

その理由は、XSLTの内部表現で"は、がとまったく同じ文字であるため"です。これらは両方ともASCIIコードポイント0x34を表します。XslCompiledTransformがその出力を生成するとき、それはそれが"そうすることが合法であるところを使用するように思われるでしょう。"それでも属性値の中に出力されると思います。

出力のように"生成されるのはあなたにとって問題ですか?"

任意の入力ファイルを使用して、VisualStudioで次の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>

ご覧のとおり、元々5文字すべてがエンティティとして表されていたとしても、アポストロフィは'どこでも生成され、引用符は"テキストノードのように生成されます。さらに、区切り文字が含まれ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ライターの作成」を参照してください。

これを回避する1つの方法は、上記と同じロジックを使用することですが、それをラップするクラスに配置します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コードが2つの場所で使用されていることを認識していませんXmlWrappingWriterが、コードを自分で消費することを考えると、このような行を削除するのはかなり安全です。null値がコンストラクターまたは(上記の場合はアクセスできない)BaseWriterプロパティに渡されないようにするだけです。

Guard.ArgumentNotNull(baseWriter, "baseWriter");

のインスタンスを作成するにはXmlWrappingWriter、必要に応じてXmlWriterを作成し、次を使用します。

KeepEntityWrapper wrap = new KeepEntityWrapper(writer);

次に、このwrap変数をXSL変換に渡すXmlWriterとして使用します。

于 2013-01-25T18:00:12.547 に答える
1

XSLTプロセッサは、文字が文字エンティティによって表されているかどうかを認識しません。これは、XMLパーサーが任意の文字エンティティをそのコード値に置き換えるためです

&quot;したがって、XSLTプロセッサは、「」、「as」、「as」、「 as 」のいずれで表されていても、まったく同じ文字を認識し&#x22;ます&#34;

XSLT 2.0では、いわゆる「文字コード表」を使用することで、必要なことを実現できます。

于 2013-01-25T18:07:05.507 に答える
1

これがあなたが望んでいたトリックです:

  1. &すべてをに置き換えます&amp;
  2. XSLTを実行する
  3. &amp;すべてをに置き換えます&
于 2017-03-23T14:47:43.263 に答える