我有一个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字符串以原始格式存储在数据库中。我需要将它们转换为后一种形式,并将其序列化为字符串。
有关实现此目标的最简单方法的任何建议吗?
答案 0 :(得分:1)
这是我对它的破解,使用Python SAX过滤器。
import sys, string from xml.sax import saxutils, handler, make_parser firstElement = True class ContentGenerator(handler.ContentHandler): def __init__(self, out = sys.stdout): handler.ContentHandler.__init__(self) self._out = out def startDocument(self): pass def startElement(self, name, attrs): global firstElement if firstElement: attrs = dict(attrs) name = "z:" + name if 'xmlns' in attrs: attrs['xmlns:z'] = attrs['xmlns'] attrs['xmlns'] = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" firstElement = False elif ':' not in name: name = "z:" + name self._out.write('<' + name) for (name, value) in attrs.items(): self._out.write(' %s="%s"' % (name, saxutils.escape(value))) self._out.write('>') def endElement(self, name): if ':' not in name: name = "z:" + name self._out.write('</%s>' % name) def characters(self, content): self._out.write(saxutils.escape(content)) def ignorableWhitespace(self, content): self._out.write(content) def processingInstruction(self, target, data): self._out.write('<?%s %s?>' % (target, data)) parser = make_parser() parser.setContentHandler(ContentGenerator()) parser.parse(sys.argv[1])
它跳转到第一个元素,使用属性进行修复,并继续在文档的其余部分中查找具有默认命名空间的所有元素。但是,您的评论表明您的文档有多个xmlns =“”属性,这意味着需要一些帮助。一般技术并不是那么糟糕,SAX管道是我们的朋友: - )。
答案 1 :(得分:0)
这可能没什么帮助,但看起来好像读者从根本上被打破了。 使用的命名空间前缀应该是无关紧要的,除非必须在属性值为QNAMS时正确绑定。
答案 2 :(得分: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读取技术从原始字符串中提取其他名称空间,然后使用上述技术创建新字符串。
答案 3 :(得分: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仍然处理字符串就好了)
答案 4 :(得分:0)