如何让LinqToXSD正确输出名称空间前缀声明?

时间:2012-05-10 23:39:40

标签: c# .net-3.5 xml-serialization xsd linq-to-xsd

我正在尝试使用LinqToXSD创建XML数据绑定类,以及包含许多导入模式的XML模式。所有模式都是 located here.

为实现此目的,我使用了以下根模式文档:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:TmatsG="http://www.spiraltechinc.com/tmats/106-13/TmatsG" elementFormDefault="unqualified">
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon" schemaLocation="TmatsCommonTypes.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsC" schemaLocation="TmatsCGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsD" schemaLocation="TmatsDGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsG" schemaLocation="TmatsGGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsH" schemaLocation="TmatsHGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsM" schemaLocation="TmatsMGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsP" schemaLocation="TmatsPGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsR" schemaLocation="TmatsRGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsS" schemaLocation="TmatsSGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsT" schemaLocation="TmatsTGroup.xsd"/>
    <xs:import namespace="http://www.spiraltechinc.com/tmats/106-13/TmatsV" schemaLocation="TmatsVGroup.xsd"/>
    <xs:element name="Tmats" type="TmatsG:Tmats">
        <xs:annotation>
            <xs:documentation>Tmats Root</xs:documentation>
        </xs:annotation>
    </xs:element>
</xs:schema>

我使用Linq到XSD创建了类。然后我写了以下测试:

[TestMethod()]
public void TmatsXmlExample4()
{
    Tmats tmats = new Tmats
    {
        ProgramName = "My Program",
        OriginationDate = DateTime.Now,
    };
    tmats.PointOfContact.Add(new PointOfContactType
    {
         Address = "12345 Anywhere Street",
         Agency = "My Agency",
         Name = "Robert Harvey",
         Telephone = "111-222-3333"
    });
    Debug.Print(tmats.ToString());
}

我预计输出看起来像这样:

<Tmats>
  <TmatsG:ProgramName>My Program</TmatsG:ProgramName>
  <TmatsG:OriginationDate>2012-05-09-07:00</TmatsG:OriginationDate>
  <TmatsG:PointOfContact>
    <TmatsCommon:Name>Robert Harvey</TmatsCommon:Name>
   <TmatsCommon:Agency>My Agency</TmatsCommon:Agency>
    <TmatsCommon:Address>12345 Anywhere Street</TmatsCommon:Address>
    <TmatsCommon:Telephone>111-222-3333</TmatsCommon:Telephone>
  </TmatsG:PointOfContact>
</Tmats>

相反,我得到的是:

<Tmats>
  <ProgramName xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsG">My Program</ProgramName>
  <OriginationDate xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsG">2012-05-09-07:00</OriginationDate>
  <PointOfContact xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsG">
    <Name xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">Robert Harvey</Name>
    <Agency xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">My Agency</Agency>
    <Address xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">12345 Anywhere Street</Address>
    <Telephone xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">111-222-3333</Telephone>
  </PointOfContact>
</Tmats>

有没有办法让LinqToXSD产生预期的输出?

1 个答案:

答案 0 :(得分:1)

您应该映射每个导入的模式:

<?xml version="1.0"?>
    <xs:schema 
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:TmatsCommon="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon"
        xmlns:TmatsC="http://www.spiraltechinc.com/tmats/106-13/TmatsC"
        xmlns:TmatsD="http://www.spiraltechinc.com/tmats/106-13/TmatsD"
        xmlns:TmatsG="http://www.spiraltechinc.com/tmats/106-13/TmatsG"
        xmlns:TmatsH="http://www.spiraltechinc.com/tmats/106-13/TmatsH"
        xmlns:TmatsM="http://www.spiraltechinc.com/tmats/106-13/TmatsM"
        … 
        elementFormDefault="unqualified">

elementFormDefault 仅适用于它所在的架构,并且不会覆盖任何包含或导入中的设置。

如果要隐藏名称空间,则所有模式必须指定 elementFormDefault =“ unqualified ”。同样,如果要公开名称空间,则每个模式都必须指定 elementFormDefault = “合格

在审核单元测试后

更新

您的输入:

<Tmats 
    xmlns:TmatsG="http://www.spiraltechinc.com/tmats/106-13/TmatsG"
    xmlns:TmatsCommon="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">
    <TmatsG:ProgramName>My Project</TmatsG:ProgramName> 
    <TmatsG:OriginationDate>2012-05-15</TmatsG:OriginationDate> 

您的输出:

<Tmats> 
    <Tmats 
        xmlns:TmatsG="http://www.spiraltechinc.com/tmats/106-13/TmatsG"
        xmlns:TmatsCommon="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">
        <TmatsG:ProgramName>My Project</TmatsG:ProgramName> 
        <TmatsG:OriginationDate>2012-05-15</TmatsG:OriginationDate> 

突出的问题是标签的重复 - 一切看起来都不错,仍在努力理解为什么会发生这种情况。

星期一更新:

我认为LinqToXSD工具中存在一个错误 - 我已经完成了我能想到的每一个组合,并且不能始终如一地解决您的问题,但是......我已经设法修复了<Tmats>重复问题:

在XmlHelper文件中,更改return语句:

System.Xml.Linq.XDocument xd = System.Xml.Linq.XDocument.Parse(sb.ToString());
return xd.Root.FirstNode.ToString();

我知道这是 hack ,但它解决了问题并且LoopbackTest通过了。

如果使用Tmats类创建元素,则不会获得任何前缀,我尝试了各种属性组合,我可以做的最好是重新附加名称空间。如果您正在与外部系统交换信息,那么我确实有修复

  1. 在代码中使用您的Tmats对象
  2. 使用命名空间序列化
  3. 通过XSLT运行它以将ns映射到前缀。
  4. 我知道它很笨重,但我认为它是最好的,你将无法实际修复LinqToXSD代码。

    将名称空间映射到前缀的XSLT(您需要在'stylesheet'声明中以及'mapper'中维护名称空间集:

    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:mapper="http://mapper"
        xmlns:TmatsCommon="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon"
        xmlns:TmatsC="http://www.spiraltechinc.com/tmats/106-13/TmatsC"
        xmlns:TmatsD="http://www.spiraltechinc.com/tmats/106-13/TmatsD"
        xmlns:TmatsG="http://www.spiraltechinc.com/tmats/106-13/TmatsG"
        xmlns:TmatsH="http://www.spiraltechinc.com/tmats/106-13/TmatsH"
        xmlns:TmatsM="http://www.spiraltechinc.com/tmats/106-13/TmatsM"
        xmlns:TmatsP="http://www.spiraltechinc.com/tmats/106-13/TmatsP"
        xmlns:TmatsR="http://www.spiraltechinc.com/tmats/106-13/TmatsR"
        xmlns:TmatsS="http://www.spiraltechinc.com/tmats/106-13/TmatsS"
        xmlns:TmatsT="http://www.spiraltechinc.com/tmats/106-13/TmatsT"
        xmlns:TmatsV="http://www.spiraltechinc.com/tmats/106-13/TmatsV">
      <xsl:output omit-xml-declaration="no" indent="yes"/>
      <xsl:strip-space elements="*"/>
      <mapper:namespaces>
        <ns prefix="TmatsCommon" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon"/>
        <ns prefix="TmatsC" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsC"/>
        <ns prefix="TmatsD" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsD"/>
        <ns prefix="TmatsG" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsG"/>
        <ns prefix="TmatsH" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsH"/>
        <ns prefix="TmatsM" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsM"/>
        <ns prefix="TmatsP" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsP"/>
        <ns prefix="TmatsR" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsR"/>
        <ns prefix="TmatsS" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsS"/>
        <ns prefix="TmatsT" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsT"/>
        <ns prefix="TmatsV" uri="http://www.spiraltechinc.com/tmats/106-13/TmatsV"/>
      </mapper:namespaces>
      <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match="*[namespace-uri()=document('')/*/mapper:namespaces/*/@uri]">
      <xsl:variable name="vNS" select="document('')/*/mapper:namespaces/*[@uri=namespace-uri(current())]"/>
      <xsl:element name="{$vNS/@prefix}:{local-name()}" namespace="{namespace-uri()}" >
       <xsl:copy-of select="namespace::*[not(. = namespace-uri(current()))]"/>
       <xsl:copy-of select="@*"/>
       <xsl:apply-templates/>
      </xsl:element>
     </xsl:template>
    </xsl:stylesheet>
    

    产地:

    <Tmats>
      <TmatsG:ProgramName xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsG">My Program</TmatsG:ProgramName>
      <TmatsG:OriginationDate xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsG">2012-05-09-07:00</TmatsG:OriginationDate>
      <TmatsG:PointOfContact xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsG">
        <TmatsCommon:Name xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">Robert Harvey</TmatsCommon:Name>
        <TmatsCommon:Agency xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">My Agency</TmatsCommon:Agency>
        <TmatsCommon:Address xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">12345 Anywhere Street</TmatsCommon:Address>
        <TmatsCommon:Telephone xmlns="http://www.spiraltechinc.com/tmats/106-13/TmatsCommon">111-222-3333</TmatsCommon:Telephone>
      </TmatsG:PointOfContact>
    </Tmats>
    

    好的,所以这远非理想,但是只有当您需要与需要修复xml输出的其他人进行交互时,您的代码才能在项目内部正常运行(请记住更改 elementFormDefault =在你的XSD中“合格”(或删除它) - 如果你将XSLT缓存为XslCompiledTransform,你几乎没有注意到它发生了。