Фильтрация нежелательных дочерних узлов XML, а также фильтрация родительских узлов с помощью XSLT или XPATH - PullRequest
0 голосов
/ 24 января 2019

Я совершенно заблудился, пытаясь подобрать XLST для одноразового проекта (анализ загруженной информации о схеме Salesforce для взаимосвязей между таблицами на проприетарном языке сценариев, который в основном просто дает мне XPATH, XSLT и циклы while -- и я никогда не слышал о XSLT до сегодняшнего дня ... он выглядит многообещающе для второй половины моих потребностей в фильтрах) .

У меня есть входной XML, который выглядит следующим образом:

<result>
    <custom>True</custom>
    <createable>False</createable>
    <fields>
        <createdBy>Joe</createdBy>
        <name>field1</name>
        <referenceTo>otherPlaceXYZ</referenceTo>
        <type>reference</type>
    </fields>
    <fields>
        <createdBy>Joe</createdBy>
        <name>field2</name>
    </fields>
    <fields>
        <createdBy>Joe</createdBy>
        <name>field3</name>
        <referenceTo>otherPlaceABC</referenceTo>
        <type>reference</type>
    </fields>
    <name>CoolName</name>
    <label>A label</label>
    <searchable>False</searchable>
</result>

Я хочу сделать 2 типа фильтров:

  1. Выбрасывать любые <fields>...</fields> узлы, у которых нет <type>reference</type> подузла
  2. В данных, которыеостается, выбрасывая детей <result>...</result>, которые не <fields>...</fields>, <name>...</name> или <label>...</label>, а также выбрасывая детей <fields>...</fields>, которые не <name>...</name> или <referenceTo>...</referenceTo> (хотя я не был бы против оставить в <type>...</type>, если это делает код проще) .Обратите внимание, что на самом деле у меня есть 5 или 6 полей, которые я хочу сохранить в «полях» (из десятков в файле), но в этом примере это коротко и привлекательно.Аналогично, есть десятки детей с «результатом», которые меня не волнуют.

Я бы хотел, чтобы мои выходные данные выглядели так:

<result>
    <fields>
        <name>field1</name>
        <referenceTo>otherPlaceXYZ</referenceTo>
    </fields>
    <fields>
        <name>field3</name>
        <referenceTo>otherPlaceABC</referenceTo>
    </fields>
    <name>CoolName</name>
    <label>A label</label>
</result>

Я играл на http://www.utilities -online.info / xsltransformation / , но застрял.Документация по XSLT, по-видимому, в основном ориентирована на выполнение гораздо более сложных преобразований данных, чем «тот же XML-файл, только меньшего размера», поэтому я изо всех сил пытаюсь найти самый простой способ выполнить эту работу.

Есть какие-нибудь указатели?

Я дошел до этого благодаря удалению родительского узла, если дочерний узел отсутствует в xml, с использованием xslt , но я не уверен, что даже лаюдерево, учитывая мое последнее желание на выходе.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <!--Identity template to copy all content by default-->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>


    <xsl:template match="fields[not(type='reference')]"/>

</xsl:stylesheet>

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Я бы предпочел использовать xsl:apply-templates для фильтрации:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="/result">
    <xsl:copy>
        <xsl:apply-templates select="fields[type='reference']|name|label" />
    </xsl:copy>
</xsl:template>

<xsl:template match="fields">
    <xsl:copy>
        <xsl:apply-templates select="name|referenceTo" />
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
0 голосов
/ 24 января 2019

Вы можете сделать это, отключив один из встроенных шаблонов и создав белый список узлов для копирования:

встроенный шаблон для деактивации описан здесь, в O'Reilly :

Встроенное правило шаблона для узлов элемента и документа

Этот шаблон обрабатывает узел документа и любойсвоих детей.Эта обработка гарантирует, что рекурсивная обработка будет продолжаться, даже если для данного элемента не объявлено ни одного шаблона:

<xsl:template match="*|/">
   <xsl:apply-templates/>
</xsl:template>

Так что ваша таблица стилей XSLT-1.0 может выглядеть следующим образом:

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

    <!-- Deactivate built-in template for elements -->
    <xsl:template match="*" />

    <!-- Apply the white list of nodes to copy -->
    <xsl:template match="/ | fields[type/text() = 'reference'] | result | result/name | result/label | fields/name | fields/referenceTo | @* | text()">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Например, result/name выбирает только name s, которые являются потомками result.

Выходные данные:

<?xml version="1.0"?>
<result>
    <fields>
        <name>field1</name>
        <referenceTo>otherPlaceXYZ</referenceTo>
    </fields>
    <fields>
        <name>field3</name>
        <referenceTo>otherPlaceABC</referenceTo>
    </fields>
    <name>CoolName</name>
    <label>A label</label>
</result>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...