我想使用 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/