1

我有一个类似于以下内容的 XML (XAML) 字符串:

<Zot xmlns="clr-namespace:A.B;assembly=A"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Zot>

Silverlight XamlReader 类无法加载此字符串,它需要一个特定的默认命名空间:

<z:Zot 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:z="clr-namespace:A.B;assembly=A"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</z:Zot>

(WPF XamlReader 不会显示这种烦人的行为)

原始格式的 XML 字符串以原始格式存储在数据库中。我需要将它们转换为后一种形式,并将其序列化为字符串。

关于实现这一目标的最简单方法的任何建议?

4

5 回答 5

1

这是我的破解,使用 Python SAX 过滤器。

导入系统,字符串

从 xml.sax 导入 saxutils、处理程序、make_parser

第一个元素 = 真

类 ContentGenerator(handler.ContentHandler):

    def __init__(self, out = sys.stdout):
        handler.ContentHandler.__init__(self)
        self._out = out

    def startDocument(self):
        经过

    def startElement(self, name, attrs):
        全局第一元素
        如果是第一个元素:
            属性 = 字典(属性)
            名称 = "z:" + 名称
            如果 attrs 中有“xmlns”:
                attrs['xmlns:z'] = attrs['xmlns']
            attrs['xmlns'] = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            第一个元素 = 假
        elif ':' 不在名称中:
            名称 = "z:" + 名称
        self._out.write('<' + name)
        attrs.items() 中的(名称,值):
            self._out.write(' %s="%s"' % (name, saxutils.escape(value)))
        self._out.write('>')

    def endElement(自我,姓名):
        如果':'不在名称中:
            名称 = "z:" + 名称
        self._out.write('</%s>' % name)

    def 字符(自我,内容):
        self._out.write(saxutils.escape(content))

    def ignorableWhitespace(self, content):
        self._out.write(内容)

    def processingInstruction(自我,目标,数据):
        self._out.write('<?%s %s?>' % (target, data))

解析器 = make_parser()
parser.setContentHandler(ContentGenerator())
parser.parse(sys.argv[1])

它跳转到第一个元素,处理属性,并继续在文档的其余部分中查找具有默认命名空间的所有元素。但是,您对文档有多个 xmlns="" 属性的评论意味着这需要一些帮助。通用技术还不错,SAX 管道是我们的朋友 :-)。

于 2009-04-05T02:59:42.437 回答
0

这可能没有多大帮助,但似乎所说的读者从根本上被打破了。使用的命名空间前缀应该是无关紧要的,除非如果属性值为 QNAmes,则必须正确绑定它。

于 2009-04-04T04:56:54.083 回答
0

这可能会有所帮助。

    using System;
    using System.Linq;
    using System.Collections;
    using System.Collections.Generic;
    using System.Xml;
    using System.Xml.Linq;

    public class MainClass 
    {
        public static void Main() 
        {
            XNamespace nameSpace = "http://www.microsoft.com";

            XElement xBooks = new XElement(nameSpace + "Books",
              new XAttribute(XNamespace.Xmlns + "linqdev", nameSpace),
            new XElement(nameSpace + "BookParticipant"));

            XmlDocument xdoc = new XmlDocument();
            xdoc.LoadXml(xBooks.ToString());
            xdoc.Save("c:\\xmloutput.xml");

        }
    }

这将输出(来自 XmlDocument xdoc,虽然实际上不需要 XmlDocument 行,但我只是将它们包含在示例中以显示使用):

<linqdev:Books xmlns:linqdev="http://www.microsoft.com">
  <linqdev:BookParticipant />
</linqdev:Books> 

您可以使用一些 xml 读取技术从原始字符串中提取其他名称空间,然后使用上述技术创建新字符串。

于 2009-04-04T05:05:26.620 回答
0

也许你可以用这个: http ://www.cnblogs.com/sheva/archive/2006/08/28/488915.html

于 2009-04-14T20:42:31.220 回答
0

我能想到的最好的方法是为任何具有默认 xmlns 属性的元素提供不同的命名空间前缀的样式表。由于我的文档有多个 xmlns="..." 属性,因此将递归地应用到树中。

如果它对其他人有用,这里是......虽然我的 XSL 技能主要基于谷歌:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:ms="urn:schemas-microsoft-com:xslt"   
    >
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>    

    <xsl:variable name="root_default_ns" select="namespace-uri(/*)" />

    <xsl:template match="node()|text()">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="node() | text()"/>
        </xsl:copy>
    </xsl:template>


    <xsl:template match="*">
        <xsl:param name="old_default_ns" select="$root_default_ns"/>
        <xsl:param name="new_default_ns" />

        <!-- match any element in the source default namespace -->
    <xsl:if test="namespace-uri() = $old_default_ns">
          <xsl:element name="ns_{$new_default_ns}:{local-name()}" namespace="{$old_default_ns}">
              <xsl:copy-of select="@*"/>
               <xsl:apply-templates select="node() | text()">
                   <xsl:with-param name="old_default_ns" select="$old_default_ns" />
                   <xsl:with-param name="new_default_ns" select="$new_default_ns" />
           </xsl:apply-templates>
          </xsl:element>
        </xsl:if>

        <!-- match any element with a prefix qualified namespace -->
        <xsl:if test="namespace-uri() != $old_default_ns and contains(name(), ':')"> 
          <xsl:element name="{name()}" namespace="{namespace-uri()}">
               <xsl:copy-of select="@*"/>
               <xsl:apply-templates select="node() | text()">
                   <xsl:with-param name="old_default_ns" select="$old_default_ns" />
                   <xsl:with-param name="new_default_ns" select="$new_default_ns" />
           </xsl:apply-templates>
          </xsl:element>
    </xsl:if>

        <!-- match any element *without* a prefix qualified namespace -->
        <xsl:if test="namespace-uri() != $old_default_ns and contains(name(), ':') = false"> 
      <xsl:variable name="new_ns" select="count(ancestor::*)" />

          <xsl:element name="ns_{$new_ns}:{name()}" namespace="{namespace-uri()}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" >
               <xsl:copy-of select="@*"/>
               <xsl:apply-templates select="node() | text()">
                   <xsl:with-param name="old_default_ns" select="namespace-uri()" />
                   <xsl:with-param name="new_default_ns"><xsl:value-of select="$new_ns" /></xsl:with-param>
           </xsl:apply-templates>
          </xsl:element>
        </xsl:if>

    </xsl:template>

    <!-- match root element only, and inject Silverlight namespace -->
    <xsl:template match="/*">
       <xsl:element name="ns_root:{local-name()}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" namespace="{$root_default_ns}">
          <!-- inject the Silverligth ns -->
         <xsl:variable name="dummy">
           <Dummy/>
         </xsl:variable>
         <xsl:copy-of select="ms:node-set($dummy)/*/namespace::*"/>
         <xsl:copy-of select="@*"/>
         <xsl:apply-templates select="node() | text()">
           <xsl:with-param name="old_default_ns" select="$root_default_ns" />
           <xsl:with-param name="new_default_ns">root</xsl:with-param>
         </xsl:apply-templates>
      </xsl:element>
    </xsl:template>

 </xsl:stylesheet>

不幸的是,在跳过这个圈之后,我得到了一个 XAML 字符串,它现在符合 XamlReader 期望的约定,但会产生一个 System.ExecutionEngineException (WPF XamlReader 仍然可以很好地处理字符串)

于 2009-04-05T00:17:32.687 回答