我想使用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,但它不涉及参考。
答案 0 :(得分:3)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="vUppercase" select="'QWERTYUIOPASDFGHJKLZXCVBNM'"/>
<xsl:variable name="vLowercase" select="'qwertyuiopasdfghjklzxcvbnm'"/>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:if test="parent::*/parent::*">
<xsl:attribute name="id">
<xsl:value-of select="translate(name(),
$vUppercase,
$vLowercase)"/>
<xsl:number level="any"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates mode="ref"/>
</xsl:copy>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*" mode="ref">
<xsl:copy>
<xsl:attribute name="ref">
<xsl:value-of select="translate(name(),
$vUppercase,
$vLowercase)"/>
<xsl:number level="any"/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输出:
<root>
<A>
<B ref="b1" />
</A>
<B att="val" id="b1">
<C ref="c1" />
</B>
<C id="c1">
someData
</C>
<A>
<B ref="b2" />
<B ref="b3" />
</A>
<B id="b2">
someOtherData
</B>
<B id="b3">
moreData
</B>
</root>
反向样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kElementById" match="*[@id]" use="@id"/>
<xsl:key name="kElementByRef" match="*[@ref]" use="@ref"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[key('kElementByRef',@id)]|
*[key('kElementByRef',@id)]/@id"/>
<xsl:template match="*[@ref]">
<xsl:for-each select="key('kElementById',@ref)">
<xsl:call-template name="identity"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
输出:
<root>
<A>
<B att="val">
<C>
someData
</C>
</B>
</A>
<A>
<B>
someOtherData
</B>
<B>
moreData
</B>
</A>
</root>
答案 1 :(得分:3)
此转化:
<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>
答案 2 :(得分:2)