2017-01-30 3 views
0

У меня есть следующий XML:XSLT: удаление дочерних узлов, не повторяя XPath

<?xml version="1.0"?> 
<Transaction> 
    <Product> 
     <ProductRq> 
      <ContactInfo> 
       <!-- several child elements --> 
      </ContactInfo> 
      <OrderInfo> 
       <!-- several child elements --> 
      </OrderInfo> 
      <ProductInfo> 
       <!-- several child elements --> 
      </ProductInfo> 
      <AddressInfo> 
       <!-- several child elements --> 
      </AddressInfo> 
      <AuditInfo> 
       <!-- several child elements --> 
      </AuditInfo> 
      <DeliveryInfo> 
       <!-- several child elements --> 
      </DeliveryInfo> 
     </ProductRq> 
    </Product> 
</Transaction> 

Для краткости я опустил еще несколько детей в <ProductRq> тег, который содержит 4 или 5 больше дочерних элементов сродни до <OrderInfo> и <CustomerInfo>, а также дочерние узлы элементов * Info.

Мне нужно удалить дочерние элементы таких элементов, как Order и <CustomerInfo>, сохраняя при этом * Информационный тег. Из 7 тегов около 4 должны пройти этот процесс. Я не могу думать о том, как сделать это, не повторяя:

<xsl:template match="Transcation/Product/ProductRq/<tag name here>/*" /> 

для каждого ребенка <ProductRq>. Есть ли способ задействовать узел контекста (<ProductRq>) и прописать петлю через дочерние элементы, удалив их собственные дочерние узлы помимо вышеперечисленного?

EDIT:
Я добавил оставшиеся дочерние теги <ProductRq>. Все теги, кроме <AuditInfo> и <ContactInfo>, должны удалять дочерние узлы.

+0

На самом деле вам не нужно указывать полный xpath в совпадении с шаблонами, вы можете просто выполнить ''. Вам нужно будет только квалифицировать его полным путем, если один и тот же элемент может встречаться на разных уровнях иерархии, и вам нужно их отличить. –

+0

Я думаю, что есть шанс, что некоторые дочерние элементы ProductRq могут повториться для разных тегов дальше документа, но ProducerRq уникален, так что ProducerRq/ будет достаточно? – jbailie1991

+0

@ jbailie1991 - вам действительно нужно будет показать этих пропущенных детей, поскольку они очень важны для вашего вопроса. Покажите, по крайней мере, детей * ProductRq *. – Parfait

ответ

1

Одно из решений, применяя следующий XSLT:

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

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

    <!-- skip all child nodes of ProductRq except they are AuditInfo or ContactInfo --> 
    <xsl:template match="ProductRq/*[not(self::AuditInfo | self::ContactInfo)]">  
    <xsl:element name="{name(.)}" /> <!-- so create an element with this name --> 
    </xsl:template> 

</xsl:stylesheet> 

Выход:

<?xml version="1.0"?> 
<Transaction> 
    <Product> 
     <ProductRq> 
      <ContactInfo> 
       <!-- several child elements --> 
      </ContactInfo> 
      <OrderInfo/> 
      <ProductInfo/> 
      <AddressInfo/> 
      <AuditInfo> 
       <!-- several child elements --> 
      </AuditInfo> 
      <DeliveryInfo/> 
     </ProductRq> 
    </Product> 
</Transaction> 
+0

, так что третий шаблон, если я правильно понимаю, соответствует дочерним узлам ProductRq, которые не являются AuditInfo или ContactInfo, тогда проверяет, что имя элемента не пустое, а если нет, создайте новый элемент с этим именем? поэтому более или менее перезаписывать согласованные элементы с тем же тегом, кроме его пустого? – jbailie1991

+0

@ jbailie1991: Вы правы. После прочтения вашего комментария я также удалил лишний второй шаблон из ответа. Таким образом, последний (бывший третий) шаблон просто воссоздает все элементы, которые не являются «AuditInfo» или «ContactInfo» (и не имеют другого типа узла (name() = empty)) без каких-либо дочерних узлов. – zx485

+0

ах ок, это довольно круто. Таким образом, эти дочерние узлы всегда будут там, даже если они пусты, так что это может пойти дальше и отказаться от условного? Просто замените каждый найденный элемент пустой версией? – jbailie1991

0

Мне нужно удалить детей элементов, как Order и <CustomerInfo> при сохранении * Информационный тег.

Шаблон вы ищете

<!-- XSLT 2.0 and up --> 
<xsl:template match="ProductRq/*[ends-with(name(), 'Info')]/*" /> 


<!-- XSLT 1.0 variant, as ends-with() does not exist here --> 
<xsl:template match="ProductRq/*[ 
    substring-before(name(), 'Info') != '' and substring-after(name(), 'Info') = '' 
]/*" /> 
+0

Мне нравится xslt 2 один вкладыш, но это удалит всех детей из всех элементов, заканчивающихся в Info. Для моего варианта использования мне нужно сохранить дочерние элементы AuditInfo и ContactInfo, а также разбить дочерние узлы других * информационных тегов – jbailie1991

+0

@ jbailie1991 Это легко, просто добавьте исключения в выражение типа this, а не (name() = 'KeepThis' или name() = 'KeepThat') '. – Tomalak

+0

@ jbailie1991 Любые отзывы о моем ответе? Вы уже пробовали? Это сработало? Если нет, что не сработало? – Tomalak

0

Написать шаблон, соответствующий ProductRq:

<xsl:template match="ProductRq"> 
    <xsl:copy> 
    <xsl:apply-templates select="ContactInfo | OrderInfo | ProductInfo | AddressInfo"/> 
    </xsl:copy> 
</xsl:template> 

Как вы видите, положение select содержит все дочерние узлы, которые должны быть включены , По умолчанию он выполняет глубокую копию (с дочерними узлами).

Но вы написали, что некоторые узлы (например, ContactInfo и OrderInfo) должны быть скопированы только в неглубоком режиме. (. Я полагаю, что этот режим должен включать в себя копирование только дочерние текстовые узлы , но больше ничего Копирование «пустые» метки кажется странным понятие.)

Для того, чтобы иметь только неполную копию этих узлов, написать еще tempate:

<xsl:template match="ContactInfo | OrderInfo"> 
    <xsl:copy><xsl:apply-templates select="text()"/></xsl:copy> 
</xsl:template> 

Подводя итог, вы пишете имена узлов, участвующих (разделенный "|") в 2-х местах:

  • всех имен является первым шаблоном
  • имена узлов, которые должны быть мелко скопированы во втором шаблоне.

Где-то вы все равно должны писать эти имена.

+0

. Я вижу, поэтому я бы указал все дочерние узлы ProductRqs в 1-м шаблоне и определил, какие узлы я хочу, чтобы дети были разделены во втором шаблоне? Кроме того, пустые теги - для последующей системы. Я не на 100% из-за того, почему они хотят в xml, но я угадываю его для дополнительной обработки (возможно, проверки: мой сервис не требуется, поскольку он находится между двумя очередями, его единственной задачей является преобразование xml для другие системы в зависимости от заголовка, прикрепленного к объекту Exchange – jbailie1991

Смежные вопросы