How do I get LinqToXSD to properly output namespace prefix declarations?

前端 未结 1 686
清歌不尽
清歌不尽 2021-02-09 01:41

I am experimenting creating XML data binding classes with LinqToXSD and an XML Schema containing a number of imported schemas. All of the schemas are located here.

相关标签:
1条回答
  • 2021-02-09 02:14

    You should map each of the imported schemas:

    <?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 only applies to the schema that it is in and it doesn't override settings in any include or imports.

    If you want to hide namespaces then all schemas must specify elementFormDefault="unqualified". Similarly if you want to expose namespaces every schema must specify elementFormDefault="qualified"

    UPDATED after reviewing unit tests:

    Your input:

    <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> 
    

    Your output:

    <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> 
    

    The outstanding problem is the duplication of the tag - everything looks ok to me, still struggling to understand why this is happening.

    UPDATE Monday:

    I think there is a bug in the LinqToXSD tool - I've run through every combination I can think of and can't consistently work around your problem, however... I have managed to fix the <Tmats> duplication issue:

    In your XmlHelper file, change the return statement:

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

    I know it's a hack, but it fixes the problem and your LoopbackTest passes.

    You don't get any prefixes if you create elements using the Tmats class, I've tried various combinations of attributes and the best I could do was re-attach namespaces. If you are exchanging information with an external system then I do have a fix:

    1. Use your Tmats object in your code,
    2. Serialize it with namespaces,
    3. Run it through an XSLT to map ns to prefixes.

    I know it's clunky, but I reckon it's the best you're going to get short of actually fixing the LinqToXSD code.

    XSLT to map namespaces to prefixes (you need to maintain the set of namespaces in 'stylesheet' declaration and also in the '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>
    

    Produces:

    <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>
    

    Ok, so this is far from ideal, but your code works fine internally to the project it only when you need to interact with other people that you'd need to fix the xml output (remember to change elementFormDefault="qualified" (or remove it) in your XSD) - if you cache the XSLT as a XslCompiledTransform you'd barely notice it happening at all.

    0 讨论(0)
提交回复
热议问题