1

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

文件_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:

过滤器.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>

但这不起作用...

4

2 回答 2

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>

更新:锦上添花

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

替代通用项模板(仅适用于 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>
于 2012-09-03T13:13:41.543 回答
1

您需要调整的两件事:

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

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

应用于示例 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output indent="yes"/>
    <xsl:param name="filter_xml" />
    <xsl:variable name="filter" select="document($filter_xml)" />

    <xsl:template match="/">

        <xsl:for-each select="root/item">
            <xsl:choose>
                <xsl:when test="$filter/Filtre/Bloc5/Part1/EAN[contains(., ./server)]">
                    <item>
                        <server>MAIN</server>
                        <status>PRODUCTION</status>
                    </item>
                </xsl:when>
                <xsl:when test="$filter/Filtre/Bloc5/Part2/EAN[contains(., ./server)]" >
                    <item>
                        <server>BACKUP</server>
                        <status>STOPPED</status>
                    </item>
                </xsl:when >
                <xsl:otherwise>
                    <item>
                        <name>OFFLINE</name>
                        <desc>Production</desc>
                    </item>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>
于 2012-09-03T12:35:13.970 回答