XSL:将XML文件转换为另一个XML文件以对其进行过滤

时间:2012-09-03 09:41:02

标签: xml xslt filter transform xslt-2.0

它又是我,但这次我有一个真正的问题...... 我有一个XML,我必须使用另一个XML的过滤器将其转换为另一个XML

File_in.xml:

    <?xml version="1.0" encoding="ISO-8859-15"?>
    <root>
        <item>
            <server>001023541</server>
            <name>P1</name>
            <desc>Production</desc>
            <status>1</status>
            <ram>1024</ram>
            <hdd>8 To</hdd>
        </item>
        <item>
            <server>201012345</server>
            <name>P2</name>
            <desc>Production</desc>
            <status>4</status>
            <ram>2048</ram>
            <hdd>8 To</hdd>
        </item>
        <item>
            <server>120332416</server>
            <name>P1</name>
            <desc>Production</desc>
            <status>2</status>
            <ram>8196</ram>
            <hdd>8 To</hdd>
        </item>
    </root>

另一个XML:

filter.xml

    <?xml version="1.0" encoding="ISO-8859-15"?>
    <Filtre>
        <Bloc5>
            <Part1>
                <EAN>001023541</EAN>
                <EAN>012356549</EAN>
                <EAN>012356559</EAN>
                <EAN>012356569</EAN>
            </Part1>
            <Part2>
                <EAN>201012345</EAN>
                <EAN>201012346</EAN>
                <EAN>201012347</EAN>
            </Part2>
        </Bloc5>
    </Filtre>

如果/ root / item / server与/ Filtre / Bloc5 / Part1 / EAN的元素匹配,我替换

        <item>
            <server>001023541</server>
            <name>P1</name>
            <desc>Production</desc>
            <status>1</status>
            <ram>1024</ram>
            <hdd>8 To</hdd>
        </item>

通过

        <item>
            <server>MAIN</server>
            <status>PRODUCTION</status>
        </item>

否则如果/ root / item / server与/ Filtre / Bloc5 / Part2 / EAN的元素匹配,我替换

        <item>
            <server>201012345</server>
            <name>P2</name>
            <desc>Production</desc>
            <status>4</status>
            <ram>2048</ram>
            <hdd>8 To</hdd>
        </item>

通过

        <item>
            <server>BACKUP</server>
            <status>STOPPED</status>
        </item>

,另一个会自动替换为:

        <item>
            <server>120332416</server>
            <name>P1</name>
            <desc>Production</desc>
            <status>2</status>
            <ram>8196</ram>
            <hdd>8 To</hdd>
        </item>

通过

        <item>
            <name>OFFLINE</name>
            <desc>Production</desc>
        </item>

我通过这种方式得到XML的名称(用于过滤):

            <!-- filter settings -->
            <xsl:param name="filter_xml" />
            <xsl:variable name="filter" select="document('$filter_xml')" />

还有我的代码:

        <xsl:for-each select="root/item">
            <xsl:choose>
                <xsl:when test="index-of(($filter/Filtre/Bloc5/Part1/EAN), ./server)">
                <item>
                    <server>MAIN</server>
                    <status>PRODUCTION</status>
                </item>
                </xsl:when>
            <xsl:when test="index-of(($filter/Filtre/Bloc5/Part2/EAN), ./server)" >
                <item>
                    <server>BACKUP</server>
                    <status>STOPPED</status>
                </item>
            </xsl:when >
            <xsl:otherwise>
                <item>
                    <name>OFFLINE</name>
                    <desc>Production</desc>
                </item>
            </xsl:otherwise>
        </xsl:for-each>

但这不起作用......

2 个答案:

答案 0 :(得分:2)

更简洁,更有效的解决方案是使用模板匹配而不是曲折的分支。我假设XSLT 2.0是因为您没有使用XSLT版本号标记您的问题,但如果您需要XSLT 1.0,则可以轻松进行调整。

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

<xsl:variable name="filter" select="document('filter.xml')/*" />

<xsl:template match="/" >
 <root>
   <xsl:apply-templates select="*/item" />
 </root>
</xsl:template>

<xsl:template match="item[server=$filter/Bloc5/Part1/EAN]" >
  <item>
    <server>MAIN</server>
    <status>PRODUCTION</status>
  </item>
</xsl:template>

<xsl:template match="item[server=$filter/Bloc5/Part2/EAN]" >
  <item>
    <server>BACKUP</server>
    <status>STOPPED</status>
  </item>
</xsl:template>

<xsl:template match="item" >
  <item>
    <name>OFFLINE</name>
    <desc>Production</desc>
  </item>
</xsl:template>

</xsl:stylesheet>

更新:锦上添花

感谢您的接受。作为锦上添花,您还可以使用此 ONE 更通用和可扩展的模板替换前两个项目模板。但它是否更简单或更复杂是值得商榷的。

替代通用项目模板(仅适用于XSLT 2.0)...

<xsl:template match="item[server=$filter/Bloc5/*/EAN]" >
  <xsl:variable name="part-no"
    select="substring-after(local-name(($filter/Bloc5/*[EAN=current()/server])[1]),
            'Part') cast as xs:integer" />
  <xsl:copy>
    <server><xsl:value-of select="('MAIN'      ,'BACKUP' )[$part-no]" /></server>
    <status><xsl:value-of select="('PRODUCTION','STOPPED')[$part-no]" /></status>
  </xsl:copy>
</xsl:template>

答案 1 :(得分:1)

您需要调整两件事:

  1. document()的路径必须是过滤变量的值。您当前正在传递字符串“$ filter”。你需要改变 <xsl:variable name="filter" select="document('$filter_xml')" /><xsl:variable name="filter" select="document($filter_xml)" />

  2. contains()函数需要每个参数的字符串输入。为了评估针对每个过滤器contains()的{​​{1}}测试,请在EAN元素的谓词过滤器内执行测试。例如,将EAN更改为<xsl:when test="index-of(($filter/Filtre/Bloc5/Part1/EAN), ./server)">。如果匹配,则结果将至少为<xsl:when test="$filter/Filtre/Bloc5/Part1/EAN[contains(., ./server)]">,在测试中评估为EAC

  3. 应用于示例XSLT:

    true()