c# - 使用 ref 属性展平 xml 文件

标签 c# xml xslt

我想使用 C# 以编程方式扁平化 xml 数据文件(请注意,这不是架构、.xsd 文件)(因此外部 xml 编辑器将无法工作,除非它具有 API)。对于示例树结构:

<root>
    <A>
        <B att="val">
            <C>
                someData
            </C>
        </B>
    </A>
    <A>
        <B>
             someOtherData
        </B>
        <B>
            moreData
        </B>
    </A>
</root>

我想将其展平为:

<root>
    <A>
        <B ref="b1" />
    </A>
    <A>
        <B ref="b2" />
        <B ref="b3" />
    </A>
    <B id="b1" att="val">
         <C ref="c1" />
    </B>
    <B id="b2">
        someOtherData
    </B>
    <B id="b3">
        moreData
    </B>
    <C id="c1">
         someData
    </C>
</root>

有没有办法使用 C# 实现此目的?

有没有办法将平面 xml 转换回树结构?我想要尽可能通用的东西,这样任何 xml 文件都可以这样展平。

有一个similar question on so ,但它不处理 refs。

最佳答案

这个转换:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="Lower" select=
  "'abcdefghijklmnopqrstuvwxyz'"
  />

 <xsl:variable name="vUpper" select=
  "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"
  />

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

 <xsl:template match="/*">
  <root>
    <xsl:apply-templates select="node()"/>
    <xsl:apply-templates select="/*/*//*" mode="extract">
     <xsl:sort select="count(ancestor::*)" data-type="number"/>
    </xsl:apply-templates>
  </root>
 </xsl:template>

 <xsl:template match="*[ancestor::*[2]]">
   <xsl:variable name="vPos">
     <xsl:number level="any"/>
   </xsl:variable>

   <xsl:element name="{name()}">
     <xsl:attribute name="ref">
       <xsl:value-of select=
        "concat(translate(name(),$vUpper,$Lower),$vPos)"/>
     </xsl:attribute>
   </xsl:element>
 </xsl:template>

 <xsl:template match="*" mode="extract">
  <xsl:variable name="vPos">
   <xsl:number level="any"/>
  </xsl:variable>

  <xsl:element name="{name()}">
    <xsl:attribute name="id">
       <xsl:value-of select=
        "concat(translate(name(),$vUpper,$Lower),$vPos)"/>
    </xsl:attribute>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<root>
    <A>
        <B att="val">
            <C>
                someData
            </C>
        </B>
    </A>
    <A>
        <B>
             someOtherData
        </B>
        <B>
            moreData
        </B>
    </A>
</root>

产生完全想要的、正确的结果:

<root>
   <A>
      <B ref="b1"/>
   </A>
   <A>
      <B ref="b2"/>
      <B ref="b3"/>
   </A>
   <B id="b1" att="val">
      <C ref="c1"/>
   </B>
   <B id="b2">
             someOtherData
        </B>
   <B id="b3">
            moreData
        </B>
   <C id="c1">
                someData
            </C>
</root>

逆向变换是:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kElbyId" match="*" use="@id"/>

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

 <xsl:template match="*[@ref]">
  <xsl:apply-templates mode="deepen"
       select="key('kElbyId',@ref)"/>
 </xsl:template>

 <xsl:template match="*[@id]"/>
 <xsl:template match="*[@id]" mode="deepen">
  <xsl:copy>
   <xsl:apply-templates
        select="@*[not(name()='id')] | node()"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

此时,对上述扁平化转换的结果进行反向转换,生成初始 XML 文档:

<root>
   <A>
      <B att="val">
         <C>
                someData
            </C>
      </B>
   </A>
   <A>
      <B>
             someOtherData
        </B>
      <B>
            moreData
        </B>
   </A>
</root>

关于c# - 使用 ref 属性展平 xml 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4266816/

相关文章:

c# - 如何将多个异步方法设置到队列中?

xml - 除了使用扩展之外,如何在 XSLT 中处理自定义命名空间?

xslt - XSl——需要转型帮助

java - 使用 XSLT 转换 XML 和保留 Unicode 字符

pdf - 使用apache fop 0.95在pdf中从左到右显示阿拉伯语文本

c# - 在预编译事件中修改 .cs 文件

c# - 监控windows访问的文件

c# - 将 IntPtr 解码为 MultiString

Perl 中的 XML 解析问题

java - 如何在我的 Android 应用程序上添加分享按钮