【问题标题】:Replace element in XML from a template从模板中替换 XML 中的元素
【发布时间】:2017-05-11 13:26:40
【问题描述】:

我需要用自定义处理指令替换部分 XSL 样式表。我们的想法是有一个这样的默认样式表:

<xsl:stylesheet xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
   <Placeholder />
</xsl:stylesheet>

元素&lt;Placeholder/&gt; 应该在运行时用自定义模板替换,例如喜欢:

var template = "<xsl:template match='/'>Today: <xsl:value-of select='Details/@date)'/>.</xsl:template>"

到目前为止我尝试了什么?

第一种方法不是使用占位符元素,而是使用具有{0} 的字符串格式而不是元素。但我无法在我的最终解决方案中使用该选项,尽管它工作正常。

相反,我尝试从模板创建 XElement 并替换占位符元素:

var document = XDocument.Parse(/* above xml */);    // works fine
document.Root.Element("Placeholder").ReplaceWith(
    XElement.Parse(template)                        // causes XmlException
);

不幸的是,这导致System.Xml.XmlException

'xsl' 是一个未声明的前缀。第 1 行,第 2 位。

有没有简单的方法来解决这个问题?

【问题讨论】:

    标签: c# .net xml


    【解决方案1】:

    具体来说,你的错误信息是因为你试图解析这个 XML:

    <xsl:template match='/'>Today: <xsl:value-of select='Details/@date)'/>.</xsl:template>
    

    此 XML 包含具有名称空间前缀的元素 - xsl - 但您没有声明它。如果您在 template 变量中声明命名空间,您应该能够正确解析它。

    试试这个:

    var template = "<xsl:template xmlns:xsl='http://www.w3.org/1999/XSL/Transform' match='/'>Today: <xsl:value-of select='Details/@date)'/>.</xsl:template>";
    

    我在运行您的代码时得到这个结果:

    <xsl:stylesheet xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:template xmlns:xsl="http://www.w3.org/1999/XSL/Transform" match="/">Today: <xsl:value-of select="Details/@date)" />.</xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 虽然一个合适的解决方案我倾向于获取文档的字符串表示,但将占位符替换为@Dariusz 建议的字符串操作和 XDocument.Parse() 再次结果。否则我需要使用字符串操作将命名空间声明插入到模板中,因为我按原样获取模板。
    • 我的回答专门解释了您的问题,并为您提供了发生问题的原因以及解决代码问题的方法。如果这实际上不是您想要的,那么为什么要问这个具体问题呢?您的问题标题是“替换 XML 中的元素” - 然后您改变主意并希望使用字符串替换来获得答案。你写了“问题是解析我作为字符串得到的 xsl 模板。” - 这解释了这个问题。
    • 别误会我的意思。正如我所说,您为问题提供了合适的解决方案和答案。感谢那。我刚刚提到我将 xsl 模板作为字符串获取。所以我有两个选择,将命名空间添加到字符串或替换 XDocument 的字符串表示中的占位符,如前所述。最好我正在寻找一个没有任何字符串操作的选项......
    • 字符串操作比 XDocument 快得多,这是真的,但代价是在替换部分字符串时可能会生成无效的 XML(我以前做过,它让我疯狂调试!) .
    【解决方案2】:

    考虑改为对字符串执行所有替换操作,然后解析生成的文档。

    如果您坚持按照自己的方式进行操作,请确保将 xsl 前缀作为命名空间 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 添加到您的文档中,然后它应该被正确解析。

    【讨论】:

    • 正如我上面写的。我在这里只能使用XDocument。文档本身具有所有必要的名称空间。问题是将我得到的 xsl-Template 解析为字符串。
    • 您可以轻松添加命名空间,先添加 > 空格 + xmlns 声明。字符串操作不是很昂贵。
    【解决方案3】:

    啊……我找到了我需要的东西。感谢https://stackoverflow.com/a/3584742/5835794

            XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
            ns.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
            XmlParserContext parserContext = new XmlParserContext(null, ns, null, XmlSpace.None);
            XmlTextReader reader = new XmlTextReader(template, XmlNodeType.Element, parserContext);
            var element = XElement.Load(reader);
            xsl.Root.Element("Placeholder").ReplaceWith(element);
    

    【讨论】:

      【解决方案4】:

      不是修改包含样式表的文档,XSLT 的做法是添加一个自定义层。自定义层是导入主样式表并覆盖其一个或多个组件的样式表模块。

      将样式表中的&lt;placeholder/&gt;替换为

      &lt;xsl:template name="placeholder"/&gt;

      然后在您的自定义层中,执行

      <xsl:import href="base-stylesheet.xsl"/>
      <xsl:template name="placeholder">
         ... custom logic goes here ...
      </xsl:template>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-06
        • 2016-04-25
        • 1970-01-01
        • 2015-03-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多