XPATH не извлекает узел II

Я нахожусь в процессе изучения XPath, и во время практики с примером файла xml, который я нашел в Интернете, приложение не может отображать какие-либо значения после внедрения файла XSL в проект. Любые советы относительно того, что я упускаю или делаю неправильно, очень ценятся.

XML-файл:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <Customers>
        <Customer>
            <Id>1</Id>
            <FirstName>Joe</FirstName>
            <Surname>Doe</Surname>
        </Customer>
   </Customers>
    <Customers>
          <Customer>
            <Id>2</Id>
            <FirstName>Mary</FirstName>
            <Surname>Brown</Surname>
        </Customer>
    </Customers>
    <Customers>
        <Customer>
            <Id>3</Id>
            <FirstName>Paul</FirstName>
            <Surname>Smith</Surname>
        </Customer>
    </Customers>
    </root>

XSL:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:template match ="/">
        <root>
            <xsl:apply-templates select ="//Customers"/>
        </root>
    </xsl:template>
    <xsl:template match ="//Customer">
        <Customer>
            <xsl:attribute name="Id">
                <xsl:value-of select="Id"/>
            </xsl:attribute>
            <xsl:attribute name="FirstName">
                <xsl:value-of select="FirstName"/>
            </xsl:attribute>
            <xsl:attribute name="Surname">
                <xsl:value-of select="Surname"/>
            </xsl:attribute>
        </Customer>
    </xsl:template>
</xsl:stylesheet>

ASPX:

<asp:XmlDataSource ID="XmlDataSource1" runat="server" 
            DataFile="~/xml/Sample-no-attributes.xml" 
            TransformFile="~/xml/Sample-no-attributes.xsl"
            XPath="/root/Customers">
      </asp:XmlDataSource>

        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
            DataSourceID="XmlDataSource1">
            <Columns>
                 <asp:TemplateField HeaderText="CustomerID">
            <ItemTemplate>
                <%# XPath("Customer/Id")%>
             </ItemTemplate>
            </asp:TemplateField>

            <asp:TemplateField HeaderText="First Name">
            <ItemTemplate>
                <%# XPath("Customer/FirstName")%>
             </ItemTemplate>
            </asp:TemplateField>

             <asp:TemplateField HeaderText="Surname">
            <ItemTemplate>
                <%# XPath("Customer/Surname")%>
             </ItemTemplate>
            </asp:TemplateField>
            </Columns>
        </asp:GridView>

Пожалуйста, помогите мне понять, что я здесь делаю неправильно.


person user1724708    schedule 04.08.2013    source источник
comment
Какова цель TransformFile в этом сценарии? Похоже, это сработало бы, если бы вы удалили этот атрибут, изменили основной XPath на /root/Customers/Customer и изменили другие XPath на Id, FirstName и т. д.   -  person JLRishe    schedule 04.08.2013
comment
Спасибо, ... Я использовал файл преобразования, учитывая, что Visual Studio сгенерировала ошибку при попытке прочитать файл xml. Он будет читать файл xml только при использовании метода атрибута.   -  person user1724708    schedule 04.08.2013


Ответы (1)


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

<root>
    <Customer Id="1" FirstName="Joe" Surname="Doe"/>
    <Customer Id="2" FirstName="Mary" Surname="Brown"/>
    <Customer Id="3" FirstName="Paul" Surname="Smith"/>
</root>

Если вы заметили, здесь нет вхождений элементов Customers, но выражение XPath в вашем asp:XmlDataSource — "/root/Customers".

Предполагая, что вы действительно хотите удалить элемент Customers, вам сначала нужно соответствующим образом изменить выражение Xpath.

XPath="/root/Customer"

Но у вас также есть проблема с выражениями XPath в ваших шаблонах элементов.

    <ItemTemplate>
        <%# XPath("Customer/Id")%>
    </ItemTemplate>

С текущим исправлением вам нужно будет удалить Customer из выражения, поскольку теперь вы будете позиционироваться на элементе Customer. Кроме того, в выходном XML Id теперь является атрибутом, а не дочерним элементом. Это означает, что ваш Xpath должен быть таким (обратите внимание на символ @, который будет использоваться для атрибутов)

    <ItemTemplate>
        <%# XPath("@Id")%>
    </ItemTemplate>

Попробуйте этот ASPX

 <asp:XmlDataSource ID="XmlDataSource1" runat="server" 
        DataFile="~/Sample-no-attributes.xml" 
        TransformFile="~/Sample-no-attributes.xsl"
        XPath="/root/Customer">
  </asp:XmlDataSource>

    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
        DataSourceID="XmlDataSource1">
        <Columns>
             <asp:TemplateField HeaderText="CustomerID">
        <ItemTemplate>
            <%# XPath("@Id")%>
         </ItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField HeaderText="First Name">
        <ItemTemplate>
            <%# XPath("@FirstName")%>
         </ItemTemplate>
        </asp:TemplateField>

         <asp:TemplateField HeaderText="Surname">
        <ItemTemplate>
            <%# XPath("@Surname")%>
         </ItemTemplate>
        </asp:TemplateField>
        </Columns>
    </asp:GridView>

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

<xsl:apply-templates select ="//Customers"/>

Но у вас нет шаблона, соответствующего Customers в вашем XSLT. Когда это происходит, применяются встроенные шаблоны XSLT. Они выводят любые текстовые узлы внутри элемента, а затем ищут шаблоны, соответствующие его дочерним элементам. Но он не выведет сам элемент. Таким образом, вы теряете элемент Клиенты.

Чтобы сохранить его, вы можете добавить следующий шаблон

 <xsl:template match ="Customers">
    <Customers>
      <xsl:apply-templates select ="Customer"/>
    </Customers>
 </xsl:template>

Однако здесь лучше использовать XSLT Identity Transform, чтобы скопировать существующие элементы.

Попробуйте этот XLST, в котором сохранен элемент Customers. Обратите внимание, что вам не нужны явные шаблоны для соответствия Root и Customers. Также обратите внимание на использование шаблонов значений атрибутов для вывода атрибутов каждого элемента Customer, что делает код менее подробным.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">

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

  <xsl:template match ="//Customer">
    <Customer Id="{Id}" FirstName="{FirstName}" Surname="{Surname}" />
  </xsl:template>
</xsl:stylesheet>

Если бы вы использовали этот XSLT, XPath asp:XmlDataSource остался бы как «/root/Customers», но XPath ItemTemplates был бы <%# XPath("Customer/@Id")%>

person Tim C    schedule 04.08.2013
comment
Все верно, но я не вижу смысла в использовании XSLT в первую очередь здесь, когда так же легко получить прямой доступ к XML. - person JLRishe; 04.08.2013
comment
Спасибо, оба решения/объяснения сработали и были очень полезны. Спасибо еще раз - person user1724708; 04.08.2013