Сравните CSV в XSLT - PullRequest
       17

Сравните CSV в XSLT

2 голосов
/ 12 декабря 2011

Это то, чего я пытаюсь достичь: у меня есть файл CSV, в котором есть данные типа 1,4,5 и т. Д. (Не фиксированная серия), и у меня есть XML, в котором повторяется определенный узел.Теперь из этого XML мне нужно удалить все те узлы, положение которых присутствует в CSV-файле.

Вот как я пытаюсь это сделать: я передаю CSV-файл в качестве параметра в XSLT и вызываюрекурсивный шаблон для печати XML.(Благодаря сообщению, которое я видел давно. Не помню адрес)

Проблема: «Это не работает»:)

Ниже приведен мой пример XML и XSLT.Мы будем благодарны за любую помощь.

XML:

<?xml version="1.0" encoding="UTF-8"?>
<Items>
    <Item IItemID="">
    </Item>
    <Item ItemID="100-8754">
    </Item>
    <Item ItemID="206-4141">
    </Item>
    <Item ItemID="">
    </Item>
</Items>

Вот XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
    <xsl:param name="ErrorPos" as="xs:string" select="'1,4'"/>
    <xsl:template match="*|/">
                <xsl:call-template name="commaSplit">
            <xsl:with-param name="dataString" select="$ErrorPos"/>
            <xsl:with-param name="position" select="1"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template name="commaSplit">
        <xsl:param name="dataString"/>
        <xsl:param name="position"/>
            Vivek
        <xsl:choose>
            <xsl:when test="contains($dataString,',')">
                <!-- Select the first value to process -->
                <xsl:call-template name="getItems">
                    <xsl:with-param name="errorPosition" select="substring-before($dataString,',')"/>
                    <xsl:with-param name="position" select="$position"/>
                </xsl:call-template>
                <!-- Recurse with remainder of string -->
                <xsl:call-template name="commaSplit">
                    <xsl:with-param name="dataString" select="substring-after($dataString,',')"/>
                    <xsl:with-param name="position" select="$position + 1"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <!-- This is the last value no need to  recurse -->
                <xsl:call-template name="getItems">
                    <xsl:with-param name="errorPosition" select="$dataString"/>
                    <xsl:with-param name="position" select="$position"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <!-- Process of individual value here -->
    <xsl:template name="getItems" match="/">
        <xsl:param name="errorPosition"/>
        <xsl:param name="position"/>
        <Items>
            <xsl:value-of select="$errorPosition"/>
            <xsl:value-of select="concat(',',$position)"/><!--Just for testing...will be replaced by copy statement-->
        </Items>
    </xsl:template>

</xsl:stylesheet>

Ответы [ 2 ]

3 голосов
/ 12 декабря 2011

Хороший вопрос, + 1.

Обратите внимание, что вы используете XSLT 2.0, но не какие-либо специальные функции XSLT 2.0 вообще.

Вот краткий и простой (одиншаблон, без рекурсии, без xsl:call-template, без xsl:choose, xsl:when, xsl:otherwise) , true Решение XSLT 2.0 :

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

 <xsl:param name="pErrorPos" as="xs:string" select="'1,4'"/>

 <xsl:variable name="vDeletePos" as="xs:integer*" select=
 " for $s in tokenize($pErrorPos, ',')
    return xs:integer($s)
 "/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="Item[position() = $vDeletePos]"/>
</xsl:stylesheet>

При применении к предоставленному документу XML :

<Items>
    <Item IItemID=""/>
    <Item ItemID="100-8754"/>
    <Item ItemID="206-4141"/>
    <Item ItemID=""/>
</Items>

желаемый, правильный результат получается :

<Items>
   <Item ItemID="100-8754"/>
   <Item ItemID="206-4141"/>
</Items>

Объяснение :

  1. Переопределение Правило идентификации .

  2. Использованиестандартная функция XPath tokenize().

2 голосов
/ 12 декабря 2011

Ваша проблема в том, что у вас есть 2 шаблона, которые совпадают с "/" корнем документа xml, чтобы правильно направлять данные, вы должны убедиться, что приоритет установлен для шаблона, который вы хотите выполнить первым! Поскольку вы используете именованные шаблоны, вы можете просто удалить атрибут match из шаблона getItems!

с этим небольшим изменением это работает, если у вас нет другого выхода?

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
    <xsl:param name="ErrorPos" as="xs:string" select="'1,4'"/>
    <xsl:template match="*|/" priority="999">
                <xsl:call-template name="commaSplit">
            <xsl:with-param name="dataString" select="$ErrorPos"/>
            <xsl:with-param name="position" select="1"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template name="commaSplit">
        <xsl:param name="dataString"/>
        <xsl:param name="position"/>
            Vivek
        <xsl:choose>
            <xsl:when test="contains($dataString,',')">
                <!-- Select the first value to process -->
                <xsl:call-template name="getItems">
                    <xsl:with-param name="errorPosition" select="substring-before($dataString,',')"/>
                    <xsl:with-param name="position" select="$position"/>
                </xsl:call-template>
                <!-- Recurse with remainder of string -->
                <xsl:call-template name="commaSplit">
                    <xsl:with-param name="dataString" select="substring-after($dataString,',')"/>
                    <xsl:with-param name="position" select="$position + 1"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <!-- This is the last value no need to  recurse -->
                <xsl:call-template name="getItems">
                    <xsl:with-param name="errorPosition" select="$dataString"/>
                    <xsl:with-param name="position" select="$position"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <!-- Process of individual value here -->
    <xsl:template name="getItems" match="/">
        <xsl:param name="errorPosition"/>
        <xsl:param name="position"/>
        <Items>
            <xsl:value-of select="$errorPosition"/>
            <xsl:value-of select="concat(',',$position)"/><!--Just for testing...will be replaced by copy statement-->
        </Items>
    </xsl:template>

</xsl:stylesheet>

С уважением, Sam

...