Фильтр XML на основе другого XML с использованием XSLT 1 - PullRequest
2 голосов
/ 03 декабря 2008

Как мы фильтруем XML-документ на основе другого XML-документа. Я должен удалить все элементы, которых нет в справочном XML. И входной xml, и lookup xml имеют одинаковые корневые элементы, мы используем XSLT 1.0.

Ex Input

<Root>
    <E1 a="1">V1</E1>
    <E2>V2</E2>
    <E3>V3</E3>
    <E5>
       <SE51>SEV1</SE51>    
       <SE52>SEV2</SE52>    
    </E5>
    <E6>
       <SE61>SEV3</SE61>    
       <SE62>SEV4</SE62>    
    </E6>
</Root>

Фильтр Xml

<Root>
    <E1 a="1"></E1>
    <E2></E2>
    <E5>
       <SE51></SE51>    
       <SE52></SE52>    
    </E5>
</Root>

Ожидаемый результат

<Root>
    <E1 a="1">V1</E1>
    <E2>V2</E2>
    <E5>
       <SE51>SEv1</SE51>    
       <SE52>SEV2</SE52>    
    </E5>
</Root>

Ответы [ 3 ]

3 голосов
/ 04 декабря 2008

Вот необходимое преобразование:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:z="inline:text.xml"
 exclude-result-prefixes="z"
 >
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <z:filter>
        <Root>
            <E1 a="1"></E1>
            <E2></E2>
            <E5>
                <SE51></SE51>
                <SE52></SE52>
            </E5>
        </Root>
    </z:filter>

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

    <xsl:template match="/">
      <xsl:apply-templates select="*[name()=name($vFilter/*)]">
        <xsl:with-param name="pFiltNode" select="$vFilter/*"/>
      </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*">
      <xsl:param name="pFiltNode"/>

      <xsl:copy>
       <xsl:copy-of select="@*"/>

       <xsl:for-each select="text() | *">
         <xsl:choose>
           <xsl:when test="self::text()">
             <xsl:copy-of select="."/>
           </xsl:when>
           <xsl:otherwise>
            <xsl:variable name="vFiltNode"
                 select="$pFiltNode/*[name()=name(current())]"/>

            <xsl:apply-templates select="self::node()[$vFiltNode]">
              <xsl:with-param name="pFiltNode" select="$vFiltNode"/>
            </xsl:apply-templates>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:for-each>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к следующему XML-документу (исходный плюс добавление <SE511>SEV11</SE511> к демонстрируют, что фильтрация работает на любом уровне :

<Root>
    <E1 a="1">V1</E1>
    <E2>V2</E2>
    <E3>V3</E3>
    <E5>
        <SE51>SEV1</SE51>
        <SE511>SEV11</SE511>
        <SE52>SEV2</SE52>
    </E5>
    <E6>
        <SE61>SEV3</SE61>
        <SE62>SEV4</SE62>
    </E6>
</Root>

желаемый результат получен :

<Root>
    <E1 a="1">V1</E1>
    <E2>V2</E2>
    <E3>V3</E3>
    <E5>
        <SE51>SEV1</SE51>
        <SE511>SEV11</SE511>
        <SE52>SEV2</SE52>
    </E5>
    <E6>
        <SE61>SEV3</SE61>
        <SE62>SEV4</SE62>
    </E6>
</Root>

Обратите внимание на следующие детали этого решения:

  1. Шаблоны применяются только к элементам, которые имеют соответствующий узел в фильтре-документе, а также ко всем текстовым узлам таких элементов.
  2. Шаблон, соответствующий элементу, передается в качестве параметра соответствующему узлу в фильтре-документе.
  3. При применении шаблонов к элементу-потомку, его соответствующий узел находится и передается в качестве ожидаемого параметра.

Наслаждайтесь!

0 голосов
/ 03 декабря 2008

Исходя из того, что я делал в прошлом, когда сталкивался с подобными проблемами, я бы предложил:

  • Написать преобразование в XSLT, для которого использовался «фильтр XML», и произвести преобразование (также в XSLT).
  • Запустите полученный XSLT на вашем входе.

Звучит (и звучит) ужасно, но я обнаружил, что это проще, чем пытаться интерпретировать описание фильтра на лету при преобразовании ввода.

0 голосов
/ 03 декабря 2008

Хммм, вы как бы говорите о слиянии (предполагая, что ваш фильтр-документ переменный). Есть несколько возможностей, которые зависят от языка, на котором вы все это реализуете. Не могли бы вы предоставить больше информации о приложении?

В противном случае я предлагаю быстрый гугл на "xslt + merge" и посмотрим, захватит ли вас какой-нибудь результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...