2013-11-12 2 views
2

Требование состоит в том, чтобы найти дублирующий элемент (BaseName) в XML и пометить родительский элемент (Учетная запись) атрибутом isDuplicate. XSL работает правильно, когда входной XML RootElement не имеет пространств имен. Когда корневой элемент имеет пространство имен, я получаю пустой объект. Я не уверен, почему пространство имен заставляет XSL генерировать пустой вывод. Любая помощь, чтобы получить правильный результат будет значительно appreciated.`XSLT2.0 дает пустой вывод, когда входной XML имеет namespcaes

входного XML пространств имен

<?xml version="1.0"?> 
    <objects xmlns="urn:s.sexmaple.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
     <Account> 
      <Id>001A00F</Id> 
      <RecordTypeId>012A00</RecordTypeId> 
      <BaseName>EFGH</BaseName> 
     </Account> 
     <Account> 
      <Id>001A0</Id> 
      <RecordTypeId>012A0</RecordTypeId> 
      <BaseName>ABCD</BaseName> 
     </Account> 
     <Account> 
      <Id>001A</Id> 
      <RecordTypeId>012A</RecordTypeId> 
      <BaseName>ABCD</BaseName> 
     </Account> 
    </objects> 

XSL

<?xml version="1.0" encoding="UTF-8"?> 
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
     <xsl:output method="xml" 
        version="1.0" 
        encoding="UTF-8" 
        indent="yes"/> 
     <xsl:strip-space elements="*" /> 
     <xsl:template match="node()|@*"> 
      <xsl:copy copy-namespaces="no"> 
       <xsl:apply-templates select="node()|@*" /> 
      </xsl:copy> 
    </xsl:template> 
    <xsl:template match="/"> 
     <xsl:variable name="Accounts"> 
      <objects> 
       <xsl:for-each select="//Account"> 
        <xsl:sort select="BaseName" /> 
        <xsl:apply-templates select="." /> 
       </xsl:for-each> 
      </objects> 
     </xsl:variable>   
     <xsl:variable name="unqentity"> 
      <objects> 
       <xsl:for-each select="$Accounts/objects/Account"> 
        <xsl:choose> 
         <xsl:when test="not(following-sibling::Account/BaseName=./BaseName) and not(preceding-sibling::Account/BaseName=./BaseName) "> 
          <xsl:copy-of select="." /> 
         </xsl:when> 
         <xsl:otherwise> 
          <Account> 
           <xsl:attribute name="isDuplicate">yes</xsl:attribute> 
           <xsl:for-each select="child::*"> 
            <xsl:element name="{name()}"> 
             <xsl:copy-of select="@*|node()" /> 
            </xsl:element> 
           </xsl:for-each> 
          </Account> 
         </xsl:otherwise> 
        </xsl:choose> 
       </xsl:for-each> 
      </objects> 
     </xsl:variable> 
     <xsl:copy-of select="$unqentity" /> 
    </xsl:template> 
</xsl:stylesheet> 

Output XML Когда вход XML ИМЕЕТ NAMESPACE

<?xml version="1.0" encoding="UTF-8"?> 
    <objects/> 

Выходной XML, если в Вводе нет пространств имен

<?xml version="1.0" encoding="UTF-8"?> 
    <objects> 
      <Account> 
       <Id>001A00F</Id> 
       <RecordTypeId>012A00</RecordTypeId> 
       <BaseName>EFGH</BaseName> 
      </Account> 
      <Account isDuplicate="yes"> 
       <Id>001A0</Id> 
       <RecordTypeId>012A0</RecordTypeId> 
       <BaseName>ABCD</BaseName> 
      </Account> 
      <Account isDuplicate="yes"> 
       <Id>001A</Id> 
       <RecordTypeId>012A</RecordTypeId> 
       <BaseName>ABCD</BaseName> 
      </Account> 
     </objects> 
+0

Есть ли причина, по которой вы не добавляете пространство имен в XSL? Или ваш вопрос, что вы не понимаете, как работают пространства имен? –

ответ

2

Если у вас есть пространство имен, это означает, что элемент в пространстве имен не совпадает с элементом без пространства имен (или даже элементом в другом пространстве имен).

Это означает, что когда вы делаете это в своем XSLT ...

<xsl:for-each select="//Account"> 

Вы ищете счета элемента, без имен, и поэтому он не будет соответствовать счету элемента в исходном XML, который находится в занятно под названием «урна: s.sexmaple.com "(что, я подозреваю, является орфографическим)

Однако, поскольку вы используете XSLT2.0, есть простой способ обойти это, указав пространство имен по умолчанию для любых выражений xpath, используя пространство имен xpath-default-namespace . Обычно этого может быть достаточно, но у вас есть несколько сложные вопросы, создавая новые элементы внутри переменной, которые затем вы затем пытаетесь выбрать.

<xsl:for-each select="$Accounts/objects/Account"> 

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

Чтобы вырезать погони, это то, что ваш XSL: таблицы стилей элемент должен выглядеть

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" 
       xmlns="urn:s.sexmaple.com" 
       xpath-default-namespace="urn:s.sexmaple.com"> 

Итак, то xpath-default-namespace="urn:s.sexmaple.com" используется для сопоставления элементов в исходном XML, в то время как xmlns="urn:s.sexmaple.com" используется чтобы элементы, созданные в переменной, имели это пространство имен и могут быть сопоставлены позже.

Сказав все это, вы скорее усложнили весь XSLT. Вы просто пытаетесь добавить атрибут IsDuplicate в Учетная запись Элементы с одинаковыми BaseName? Ну, создайте ключ для поиска дубликатов, как так

<xsl:key name="account" match="Account" use="BaseName" /> 

Тогда вы можете посмотреть дубликаты так:

  <xsl:if test="key('account', BaseName)[2]"> 
      <xsl:attribute name="isDuplicate">Yes</xsl:attribute> 
     </xsl:if> 

Попробуйте XSLT, который должен дать те же результаты

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="urn:s.sexmaple.com"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:key name="account" match="Account" use="BaseName" /> 

    <xsl:template match="Account"> 
      <xsl:copy> 
      <xsl:if test="key('account', BaseName)[2]"> 
       <xsl:attribute name="isDuplicate">Yes</xsl:attribute> 
      </xsl:if> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

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

Обратите внимание, что это нужно только для использования xpath-default-namespace, поскольку оно не создает целых новых элементов, просто копируя существующие (которые также копируют пространство имен).

0

Причина, по которой ваш входной XML без пространства имен работает с пространством имен, отсутствует, не из-за входного XML, а из-за таблицы стилей XSLT.

Когда ваш XML-файл имеет пространство имен по умолчанию, это пространство имен должно быть объявлено в самой таблице стилей.

Например, с помощью следующего XML:

<test xmlns="test.xml.schema"> 
    <element>Content</element> 
</test> 

Когда я применяю следующий XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
    <xsl:template match="/"> 
    <out> 
     <namespace>None</namespace> 
     <xsl:apply-templates /> 
    </out> 
    </xsl:template> 

    <xsl:template match="test"> 
    <test out="True">hello</test> 
    </xsl:template> 
    <xsl:template match="*"/> 

</xsl:stylesheet> 

Выход просто:

<out><namespace>None</namespace></out> 

<xsl:template match="test"> не может совпадение на тестовом элементе во входном xml, так как оно фактически test.xml.schema:test, в то время как совпадение в таблице стилей без пространства имен фактически равно :test. Таким образом, совпадение невозможно.

Однако, когда мы просто добавить пространство имен для ввода документа ADN изменить шаблон, например, так:

<xsl:stylesheet xmlns:t="test.xml.schema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
    <xsl:template match="/"> 
    <out> 
     <namespace>test.xml.schema</namespace> 
     <xsl:apply-templates /> 
    </out> 
    </xsl:template> 

    <xsl:template match="t:test"> 
    <test out="True">hello</test> 
    </xsl:template> 
    <xsl:template match="*"/> 

</xsl:stylesheet>  

Выход становится:

<out xmlns:t="test.xml.schema"> 
    <namespace>test.xml.schema</namespace> 
    <test out="True">hello</test> 
</out> 

Важно заметить, что пространство имен аббревиатурой во входном документе и XSL не обязательно должны быть одинаковыми (например, blank vs. «t»), но сами пространства имен: (например, оба пустых и «t» должны быть связаны с test.xml.schema).

Также обратите внимание, что using a default namespace in XSLT can be fraught with issues. Поэтому лучше всего использовать объявленные пространства имен в XSLT.

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