用带路径的属性重写xml

时间:2012-06-25 12:39:09

标签: xml path flat

虽然我已经看过很多关于如何将属性转换为元素的帖子,但没有一个例子可以满足我的需要。 我有一个扁平的xml,并将其转换为完整的树导向xml:

输入:

<Subsystem Name="Device Monitor">
<Group Name="ITCHealth">
    <Field Name="System\AttachedDevice\OneWire\Count" Type="Integer">0</Field>
    <Field Name="System\AttachedDevice\OneWire\Asset" Type="String">Str</Field>
    <Field Name="System\AttachedDevice\USB\Count" Type="Integer">0</Field>
    <Field Name="System\AttachedDevice\USB\Name" Type="Integer">0</Field>
    <Field Name="System\Camera\Enabled" Type="Boolean">true</Field>
    <Field Name="System\Camera\Present" Type="Boolean">true</Field>
    <Field Name="Network\BlueTooth\RadioStatus" Type="String">Str</Field>
</Group>
</Subsystem>

期望的输出:

<Subsystem Name="Device Monitor">
<Group Name="ITCHealth">
    <Group Name="System">
        <Group Name="AttachedDevice">
            <Group Name="OneWire">
                <Field Name="Count" Type="Integer">0</Field>
                <Field Name="Asset" Type="String">Str</Field>
            </Group>
            <Group Name="USB ">
                <Field Name="Count" Type="Integer">0</Field>
                <Field Name="Name" Type="Integer">0</Field>
            </Group>
        </Group>
        <Group Name="Camera">
            <Field Name="Enabled" Type="Boolean">true</Field>
            <Field Name="Present" Type="Boolean">true</Field>
        </Group>
    </Group>
    <Group Name="Network">
        <Group Name="Bluetooth">
            <Field Name="Radiostatus" Type="String">Str</Field>
        </Group>
    </Group>
</Group>
</Subsystem>

我更喜欢CSharp解决方案。

感谢您的帮助

1 个答案:

答案 0 :(得分:0)

这是一个XSLT 2.0解决方案(有几个XSLT 2.0处理器可以从C#轻松调用)。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">

    <xsl:template match="*">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Group">
        <xsl:copy>
            <xsl:call-template name="group-fields">
                <xsl:with-param name="fields" select="Field"/>
                <xsl:with-param name="depth" select="1"/>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>

    <xsl:template name="group-fields">
        <xsl:param name="fields" as="element(Field)*"/>
        <xsl:param name="depth"/>
        <xsl:for-each-group select="$fields" group-by="tokenize(@Name, '\\')[$depth]">
            <xsl:choose>
                <xsl:when test="count(current-group()) = 1 and count(tokenize(@Name, '\\')) = $depth">
                    <Field Name="{current-grouping-key()}" Type="{@Type}">
                        <xsl:value-of select="."/>
                    </Field>
                </xsl:when>
                <xsl:otherwise>
                    <Group Name="{current-grouping-key()}">
                        <xsl:call-template name="group-fields">
                            <xsl:with-param name="fields" select="current-group()"/>
                            <xsl:with-param name="depth" select="$depth + 1"/>
                        </xsl:call-template>
                    </Group>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>

</xsl:stylesheet>

与我的大部分答案不同,这是完整的并经过测试,以提供您所需的输出,至少在您提供的示例文档中。