Копирование ссылочных элементов XML - PullRequest
0 голосов
/ 08 мая 2018

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

<root>
    <users>
        <user id="1" name="user 1" />
        <user id="2" name="user 2" />
        <user id="3" name="user 3" />
    </users>
    <posts>
        <post>
            <user>1</user>
            <text>First sample post!</text>
            <status>DELETED</status>
        </post>
        <post>
            <user>2</user>
            <text>Second sample post!</text>
            <status>ACTIVE</status>
        </post>
        <post>
            <user>3</user>
            <text>Third sample post!</text>
            <status>DELETED</status>
        </post>
    </posts>
</root>

Мне нужно отфильтровать пользователей так, чтобы целевой документ содержал только АКТИВНЫЕ сообщения и тех пользователей, на которые ссылается элемент post .:

<root>
    <users>
        <user id="2" name="user 2" />
    </users>
    <posts>
        <post>
            <user>2</user>
            <text>Second sample post!</text>
        </post>
    </posts>
</root>

У меня нет доступа к изменению исходного документа, и я обязан сделать это возможным с помощью XSLT (что я очень новичок).

Я могу легко фильтровать сообщения, но я не уверен, как составить список пользователей.

Прежде чем идти дальше, я бы хотел проверить, возможно ли это.

Приветствия

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

Сначала вы должны узнать о шаблоне идентификации

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

Сам по себе он скопирует все узлы именно из исходного документа.

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

Вы не хотите post элементов, где status не "ACTIVE"? Просто имейте пустой шаблон, чтобы остановить их копирование.

<xsl:template match="post[status!='ACTIVE']" />

Аналогично, для удаления самого узла status (для копий, которые он копирует)

<xsl:template match="status" />

Для элементов user рассмотрите возможность использования xsl:key для поиска post элементов

<xsl:key name="posts" match="post" use="user" />

Тогда ваш шаблон для игнорирования пользователей будет таким ...

<xsl:template match="user[key('posts', @id)/status!='ACTIVE']" />

Соберите все это вместе, и вы получите ...

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

    <xsl:key name="posts" match="post" use="user" />

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

    <xsl:template match="post[status!='ACTIVE']" />

    <xsl:template match="status" />

    <xsl:template match="user[key('posts', @id)/status!='ACTIVE']" />
</xsl:stylesheet>
0 голосов
/ 08 мая 2018

Да, это возможно, с таблицей стилей, подобной этой:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!-- Copy asnything not overridden below -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- Copy <user> if active <post> exists -->
    <xsl:template match="users/user"><!-- don't match 'post/user' -->
        <xsl:variable name="userId" select="@id"/>
        <xsl:if test="../../posts/post[user = $userId][status = 'ACTIVE']">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

    <!-- Copy <post> if active -->
    <xsl:template match="post">
        <xsl:if test="status = 'ACTIVE'">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

    <!-- Don't copy <status> -->
    <xsl:template match="status">
    </xsl:template>

</xsl:stylesheet>

Тест

TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(new File("test.xslt")));
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new StreamSource(new File("test.xml")),
                      new StreamResult(System.out));

выход

<root>
    <users>

        <user id="2" name="user 2"/>

    </users>
    <posts>

        <post>
            <user>2</user>
            <text>Second sample post!</text>

        </post>

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