Home | History | Annotate | Download | only in parser
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "xfa/fxfa/parser/cxfa_dataexporter.h"
      8 
      9 #include <vector>
     10 
     11 #include "core/fxcrt/fx_basic.h"
     12 #include "third_party/base/stl_util.h"
     13 #include "xfa/fde/xml/fde_xml_imp.h"
     14 #include "xfa/fgas/crt/fgas_codepage.h"
     15 #include "xfa/fxfa/parser/cxfa_document.h"
     16 #include "xfa/fxfa/parser/cxfa_widgetdata.h"
     17 #include "xfa/fxfa/parser/xfa_object.h"
     18 
     19 namespace {
     20 
     21 CFX_WideString ExportEncodeAttribute(const CFX_WideString& str) {
     22   CFX_WideTextBuf textBuf;
     23   int32_t iLen = str.GetLength();
     24   for (int32_t i = 0; i < iLen; i++) {
     25     switch (str[i]) {
     26       case '&':
     27         textBuf << L"&amp;";
     28         break;
     29       case '<':
     30         textBuf << L"&lt;";
     31         break;
     32       case '>':
     33         textBuf << L"&gt;";
     34         break;
     35       case '\'':
     36         textBuf << L"&apos;";
     37         break;
     38       case '\"':
     39         textBuf << L"&quot;";
     40         break;
     41       default:
     42         textBuf.AppendChar(str[i]);
     43     }
     44   }
     45   return textBuf.MakeString();
     46 }
     47 
     48 CFX_WideString ExportEncodeContent(const CFX_WideStringC& str) {
     49   CFX_WideTextBuf textBuf;
     50   int32_t iLen = str.GetLength();
     51   for (int32_t i = 0; i < iLen; i++) {
     52     FX_WCHAR ch = str.GetAt(i);
     53     if (!FDE_IsXMLValidChar(ch))
     54       continue;
     55 
     56     if (ch == '&') {
     57       textBuf << L"&amp;";
     58     } else if (ch == '<') {
     59       textBuf << L"&lt;";
     60     } else if (ch == '>') {
     61       textBuf << L"&gt;";
     62     } else if (ch == '\'') {
     63       textBuf << L"&apos;";
     64     } else if (ch == '\"') {
     65       textBuf << L"&quot;";
     66     } else if (ch == ' ') {
     67       if (i && str.GetAt(i - 1) != ' ') {
     68         textBuf.AppendChar(' ');
     69       } else {
     70         textBuf << L"&#x20;";
     71       }
     72     } else {
     73       textBuf.AppendChar(str.GetAt(i));
     74     }
     75   }
     76   return textBuf.MakeString();
     77 }
     78 
     79 void SaveAttribute(CXFA_Node* pNode,
     80                    XFA_ATTRIBUTE eName,
     81                    const CFX_WideStringC& wsName,
     82                    bool bProto,
     83                    CFX_WideString& wsOutput) {
     84   CFX_WideString wsValue;
     85   if ((!bProto && !pNode->HasAttribute((XFA_ATTRIBUTE)eName, bProto)) ||
     86       !pNode->GetAttribute((XFA_ATTRIBUTE)eName, wsValue, false)) {
     87     return;
     88   }
     89   wsValue = ExportEncodeAttribute(wsValue);
     90   wsOutput += L" ";
     91   wsOutput += wsName;
     92   wsOutput += L"=\"";
     93   wsOutput += wsValue;
     94   wsOutput += L"\"";
     95 }
     96 
     97 bool AttributeSaveInDataModel(CXFA_Node* pNode, XFA_ATTRIBUTE eAttribute) {
     98   bool bSaveInDataModel = false;
     99   if (pNode->GetElementType() != XFA_Element::Image)
    100     return bSaveInDataModel;
    101 
    102   CXFA_Node* pValueNode = pNode->GetNodeItem(XFA_NODEITEM_Parent);
    103   if (!pValueNode || pValueNode->GetElementType() != XFA_Element::Value)
    104     return bSaveInDataModel;
    105 
    106   CXFA_Node* pFieldNode = pValueNode->GetNodeItem(XFA_NODEITEM_Parent);
    107   if (pFieldNode && pFieldNode->GetBindData() &&
    108       eAttribute == XFA_ATTRIBUTE_Href) {
    109     bSaveInDataModel = true;
    110   }
    111   return bSaveInDataModel;
    112 }
    113 
    114 bool ContentNodeNeedtoExport(CXFA_Node* pContentNode) {
    115   CFX_WideString wsContent;
    116   if (!pContentNode->TryContent(wsContent, false, false))
    117     return false;
    118 
    119   ASSERT(pContentNode->IsContentNode());
    120   CXFA_Node* pParentNode = pContentNode->GetNodeItem(XFA_NODEITEM_Parent);
    121   if (!pParentNode || pParentNode->GetElementType() != XFA_Element::Value)
    122     return true;
    123 
    124   CXFA_Node* pGrandParentNode = pParentNode->GetNodeItem(XFA_NODEITEM_Parent);
    125   if (!pGrandParentNode || !pGrandParentNode->IsContainerNode())
    126     return true;
    127   if (pGrandParentNode->GetBindData())
    128     return false;
    129 
    130   CXFA_WidgetData* pWidgetData = pGrandParentNode->GetWidgetData();
    131   XFA_Element eUIType = pWidgetData->GetUIType();
    132   if (eUIType == XFA_Element::PasswordEdit)
    133     return false;
    134   return true;
    135 }
    136 
    137 void RecognizeXFAVersionNumber(CXFA_Node* pTemplateRoot,
    138                                CFX_WideString& wsVersionNumber) {
    139   wsVersionNumber.clear();
    140   if (!pTemplateRoot)
    141     return;
    142 
    143   CFX_WideString wsTemplateNS;
    144   if (!pTemplateRoot->TryNamespace(wsTemplateNS))
    145     return;
    146 
    147   XFA_VERSION eVersion =
    148       pTemplateRoot->GetDocument()->RecognizeXFAVersionNumber(wsTemplateNS);
    149   if (eVersion == XFA_VERSION_UNKNOWN)
    150     eVersion = XFA_VERSION_DEFAULT;
    151 
    152   wsVersionNumber.Format(L"%i.%i", eVersion / 100, eVersion % 100);
    153 }
    154 
    155 void RegenerateFormFile_Changed(CXFA_Node* pNode,
    156                                 CFX_WideTextBuf& buf,
    157                                 bool bSaveXML) {
    158   CFX_WideString wsAttrs;
    159   int32_t iAttrs = 0;
    160   const uint8_t* pAttrs =
    161       XFA_GetElementAttributes(pNode->GetElementType(), iAttrs);
    162   while (iAttrs--) {
    163     const XFA_ATTRIBUTEINFO* pAttr =
    164         XFA_GetAttributeByID((XFA_ATTRIBUTE)pAttrs[iAttrs]);
    165     if (pAttr->eName == XFA_ATTRIBUTE_Name ||
    166         (AttributeSaveInDataModel(pNode, pAttr->eName) && !bSaveXML)) {
    167       continue;
    168     }
    169     CFX_WideString wsAttr;
    170     SaveAttribute(pNode, pAttr->eName, pAttr->pName, bSaveXML, wsAttr);
    171     wsAttrs += wsAttr;
    172   }
    173 
    174   CFX_WideString wsChildren;
    175   switch (pNode->GetObjectType()) {
    176     case XFA_ObjectType::ContentNode: {
    177       if (!bSaveXML && !ContentNodeNeedtoExport(pNode))
    178         break;
    179 
    180       CXFA_Node* pRawValueNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    181       while (pRawValueNode &&
    182              pRawValueNode->GetElementType() != XFA_Element::SharpxHTML &&
    183              pRawValueNode->GetElementType() != XFA_Element::Sharptext &&
    184              pRawValueNode->GetElementType() != XFA_Element::Sharpxml) {
    185         pRawValueNode = pRawValueNode->GetNodeItem(XFA_NODEITEM_NextSibling);
    186       }
    187       if (!pRawValueNode)
    188         break;
    189 
    190       CFX_WideString wsContentType;
    191       pNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, false);
    192       if (pRawValueNode->GetElementType() == XFA_Element::SharpxHTML &&
    193           wsContentType == L"text/html") {
    194         CFDE_XMLNode* pExDataXML = pNode->GetXMLMappingNode();
    195         if (!pExDataXML)
    196           break;
    197 
    198         CFDE_XMLNode* pRichTextXML =
    199             pExDataXML->GetNodeItem(CFDE_XMLNode::FirstChild);
    200         if (!pRichTextXML)
    201           break;
    202 
    203         CFX_RetainPtr<IFX_MemoryStream> pMemStream =
    204             IFX_MemoryStream::Create(true);
    205 
    206         // Note: ambiguous without cast below.
    207         CFX_RetainPtr<IFGAS_Stream> pTempStream = IFGAS_Stream::CreateStream(
    208             CFX_RetainPtr<IFX_SeekableWriteStream>(pMemStream),
    209             FX_STREAMACCESS_Text | FX_STREAMACCESS_Write |
    210                 FX_STREAMACCESS_Append);
    211 
    212         pTempStream->SetCodePage(FX_CODEPAGE_UTF8);
    213         pRichTextXML->SaveXMLNode(pTempStream);
    214         wsChildren += CFX_WideString::FromUTF8(
    215             CFX_ByteStringC(pMemStream->GetBuffer(), pMemStream->GetSize()));
    216       } else if (pRawValueNode->GetElementType() == XFA_Element::Sharpxml &&
    217                  wsContentType == L"text/xml") {
    218         CFX_WideString wsRawValue;
    219         pRawValueNode->GetAttribute(XFA_ATTRIBUTE_Value, wsRawValue, false);
    220         if (wsRawValue.IsEmpty())
    221           break;
    222 
    223         std::vector<CFX_WideString> wsSelTextArray;
    224         int32_t iStart = 0;
    225         int32_t iEnd = wsRawValue.Find(L'\n', iStart);
    226         iEnd = (iEnd == -1) ? wsRawValue.GetLength() : iEnd;
    227         while (iEnd >= iStart) {
    228           wsSelTextArray.push_back(wsRawValue.Mid(iStart, iEnd - iStart));
    229           iStart = iEnd + 1;
    230           if (iStart >= wsRawValue.GetLength())
    231             break;
    232 
    233           iEnd = wsRawValue.Find(L'\n', iStart);
    234         }
    235         CXFA_Node* pParentNode = pNode->GetNodeItem(XFA_NODEITEM_Parent);
    236         ASSERT(pParentNode);
    237         CXFA_Node* pGrandparentNode =
    238             pParentNode->GetNodeItem(XFA_NODEITEM_Parent);
    239         ASSERT(pGrandparentNode);
    240         CFX_WideString bodyTagName;
    241         bodyTagName = pGrandparentNode->GetCData(XFA_ATTRIBUTE_Name);
    242         if (bodyTagName.IsEmpty())
    243           bodyTagName = L"ListBox1";
    244 
    245         buf << L"<";
    246         buf << bodyTagName;
    247         buf << L" xmlns=\"\"\n>";
    248         for (int32_t i = 0; i < pdfium::CollectionSize<int32_t>(wsSelTextArray);
    249              i++) {
    250           buf << L"<value\n>";
    251           buf << ExportEncodeContent(wsSelTextArray[i].AsStringC());
    252           buf << L"</value\n>";
    253         }
    254         buf << L"</";
    255         buf << bodyTagName;
    256         buf << L"\n>";
    257         wsChildren += buf.AsStringC();
    258         buf.Clear();
    259       } else {
    260         CFX_WideStringC wsValue = pRawValueNode->GetCData(XFA_ATTRIBUTE_Value);
    261         wsChildren += ExportEncodeContent(wsValue);
    262       }
    263       break;
    264     }
    265     case XFA_ObjectType::TextNode:
    266     case XFA_ObjectType::NodeC:
    267     case XFA_ObjectType::NodeV: {
    268       CFX_WideStringC wsValue = pNode->GetCData(XFA_ATTRIBUTE_Value);
    269       wsChildren += ExportEncodeContent(wsValue);
    270       break;
    271     }
    272     default:
    273       if (pNode->GetElementType() == XFA_Element::Items) {
    274         CXFA_Node* pTemplateNode = pNode->GetTemplateNode();
    275         if (!pTemplateNode ||
    276             pTemplateNode->CountChildren(XFA_Element::Unknown) !=
    277                 pNode->CountChildren(XFA_Element::Unknown)) {
    278           bSaveXML = true;
    279         }
    280       }
    281       CFX_WideTextBuf newBuf;
    282       CXFA_Node* pChildNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    283       while (pChildNode) {
    284         RegenerateFormFile_Changed(pChildNode, newBuf, bSaveXML);
    285         wsChildren += newBuf.AsStringC();
    286         newBuf.Clear();
    287         pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
    288       }
    289       if (!bSaveXML && !wsChildren.IsEmpty() &&
    290           pNode->GetElementType() == XFA_Element::Items) {
    291         wsChildren.clear();
    292         bSaveXML = true;
    293         CXFA_Node* pChild = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    294         while (pChild) {
    295           RegenerateFormFile_Changed(pChild, newBuf, bSaveXML);
    296           wsChildren += newBuf.AsStringC();
    297           newBuf.Clear();
    298           pChild = pChild->GetNodeItem(XFA_NODEITEM_NextSibling);
    299         }
    300       }
    301       break;
    302   }
    303 
    304   if (!wsChildren.IsEmpty() || !wsAttrs.IsEmpty() ||
    305       pNode->HasAttribute(XFA_ATTRIBUTE_Name)) {
    306     CFX_WideStringC wsElement = pNode->GetClassName();
    307     CFX_WideString wsName;
    308     SaveAttribute(pNode, XFA_ATTRIBUTE_Name, L"name", true, wsName);
    309     buf << L"<";
    310     buf << wsElement;
    311     buf << wsName;
    312     buf << wsAttrs;
    313     if (wsChildren.IsEmpty()) {
    314       buf << L"\n/>";
    315     } else {
    316       buf << L"\n>";
    317       buf << wsChildren;
    318       buf << L"</";
    319       buf << wsElement;
    320       buf << L"\n>";
    321     }
    322   }
    323 }
    324 
    325 void RegenerateFormFile_Container(CXFA_Node* pNode,
    326                                   const CFX_RetainPtr<IFGAS_Stream>& pStream,
    327                                   bool bSaveXML = false) {
    328   XFA_Element eType = pNode->GetElementType();
    329   if (eType == XFA_Element::Field || eType == XFA_Element::Draw ||
    330       !pNode->IsContainerNode()) {
    331     CFX_WideTextBuf buf;
    332     RegenerateFormFile_Changed(pNode, buf, bSaveXML);
    333     FX_STRSIZE nLen = buf.GetLength();
    334     if (nLen > 0)
    335       pStream->WriteString((const FX_WCHAR*)buf.GetBuffer(), nLen);
    336     return;
    337   }
    338 
    339   CFX_WideStringC wsElement = pNode->GetClassName();
    340   pStream->WriteString(L"<", 1);
    341   pStream->WriteString(wsElement.c_str(), wsElement.GetLength());
    342   CFX_WideString wsOutput;
    343   SaveAttribute(pNode, XFA_ATTRIBUTE_Name, L"name", true, wsOutput);
    344   CFX_WideString wsAttrs;
    345   int32_t iAttrs = 0;
    346   const uint8_t* pAttrs =
    347       XFA_GetElementAttributes(pNode->GetElementType(), iAttrs);
    348   while (iAttrs--) {
    349     const XFA_ATTRIBUTEINFO* pAttr =
    350         XFA_GetAttributeByID((XFA_ATTRIBUTE)pAttrs[iAttrs]);
    351     if (pAttr->eName == XFA_ATTRIBUTE_Name)
    352       continue;
    353 
    354     CFX_WideString wsAttr;
    355     SaveAttribute(pNode, pAttr->eName, pAttr->pName, false, wsAttr);
    356     wsOutput += wsAttr;
    357   }
    358 
    359   if (!wsOutput.IsEmpty())
    360     pStream->WriteString(wsOutput.c_str(), wsOutput.GetLength());
    361 
    362   CXFA_Node* pChildNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    363   if (pChildNode) {
    364     pStream->WriteString(L"\n>", 2);
    365     while (pChildNode) {
    366       RegenerateFormFile_Container(pChildNode, pStream, bSaveXML);
    367       pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
    368     }
    369     pStream->WriteString(L"</", 2);
    370     pStream->WriteString(wsElement.c_str(), wsElement.GetLength());
    371     pStream->WriteString(L"\n>", 2);
    372   } else {
    373     pStream->WriteString(L"\n/>", 3);
    374   }
    375 }
    376 
    377 }  // namespace
    378 
    379 void XFA_DataExporter_RegenerateFormFile(
    380     CXFA_Node* pNode,
    381     const CFX_RetainPtr<IFGAS_Stream>& pStream,
    382     const FX_CHAR* pChecksum,
    383     bool bSaveXML) {
    384   if (pNode->IsModelNode()) {
    385     static const FX_WCHAR s_pwsTagName[] = L"<form";
    386     static const FX_WCHAR s_pwsClose[] = L"</form\n>";
    387     pStream->WriteString(s_pwsTagName, FXSYS_wcslen(s_pwsTagName));
    388     if (pChecksum) {
    389       static const FX_WCHAR s_pwChecksum[] = L" checksum=\"";
    390       CFX_WideString wsChecksum = CFX_WideString::FromUTF8(pChecksum);
    391       pStream->WriteString(s_pwChecksum, FXSYS_wcslen(s_pwChecksum));
    392       pStream->WriteString(wsChecksum.c_str(), wsChecksum.GetLength());
    393       pStream->WriteString(L"\"", 1);
    394     }
    395     pStream->WriteString(L" xmlns=\"", FXSYS_wcslen(L" xmlns=\""));
    396     const FX_WCHAR* pURI = XFA_GetPacketByIndex(XFA_PACKET_Form)->pURI;
    397     pStream->WriteString(pURI, FXSYS_wcslen(pURI));
    398     CFX_WideString wsVersionNumber;
    399     RecognizeXFAVersionNumber(
    400         ToNode(pNode->GetDocument()->GetXFAObject(XFA_HASHCODE_Template)),
    401         wsVersionNumber);
    402     if (wsVersionNumber.IsEmpty())
    403       wsVersionNumber = L"2.8";
    404 
    405     wsVersionNumber += L"/\"\n>";
    406     pStream->WriteString(wsVersionNumber.c_str(), wsVersionNumber.GetLength());
    407     CXFA_Node* pChildNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    408     while (pChildNode) {
    409       RegenerateFormFile_Container(pChildNode, pStream);
    410       pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
    411     }
    412     pStream->WriteString(s_pwsClose, FXSYS_wcslen(s_pwsClose));
    413   } else {
    414     RegenerateFormFile_Container(pNode, pStream, bSaveXML);
    415   }
    416 }
    417 
    418 void XFA_DataExporter_DealWithDataGroupNode(CXFA_Node* pDataNode) {
    419   if (!pDataNode || pDataNode->GetElementType() == XFA_Element::DataValue)
    420     return;
    421 
    422   int32_t iChildNum = 0;
    423   for (CXFA_Node* pChildNode = pDataNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    424        pChildNode;
    425        pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling)) {
    426     iChildNum++;
    427     XFA_DataExporter_DealWithDataGroupNode(pChildNode);
    428   }
    429 
    430   if (pDataNode->GetElementType() != XFA_Element::DataGroup)
    431     return;
    432 
    433   if (iChildNum > 0) {
    434     CFDE_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
    435     ASSERT(pXMLNode->GetType() == FDE_XMLNODE_Element);
    436     CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
    437     if (pXMLElement->HasAttribute(L"xfa:dataNode"))
    438       pXMLElement->RemoveAttribute(L"xfa:dataNode");
    439 
    440     return;
    441   }
    442 
    443   CFDE_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
    444   ASSERT(pXMLNode->GetType() == FDE_XMLNODE_Element);
    445   static_cast<CFDE_XMLElement*>(pXMLNode)->SetString(L"xfa:dataNode",
    446                                                      L"dataGroup");
    447 }
    448 
    449 CXFA_DataExporter::CXFA_DataExporter(CXFA_Document* pDocument)
    450     : m_pDocument(pDocument) {
    451   ASSERT(m_pDocument);
    452 }
    453 
    454 bool CXFA_DataExporter::Export(
    455     const CFX_RetainPtr<IFX_SeekableWriteStream>& pWrite) {
    456   return Export(pWrite, m_pDocument->GetRoot(), 0, nullptr);
    457 }
    458 
    459 bool CXFA_DataExporter::Export(
    460     const CFX_RetainPtr<IFX_SeekableWriteStream>& pWrite,
    461     CXFA_Node* pNode,
    462     uint32_t dwFlag,
    463     const FX_CHAR* pChecksum) {
    464   ASSERT(pWrite);
    465   if (!pWrite)
    466     return false;
    467 
    468   CFX_RetainPtr<IFGAS_Stream> pStream = IFGAS_Stream::CreateStream(
    469       pWrite,
    470       FX_STREAMACCESS_Text | FX_STREAMACCESS_Write | FX_STREAMACCESS_Append);
    471   if (!pStream)
    472     return false;
    473 
    474   pStream->SetCodePage(FX_CODEPAGE_UTF8);
    475   return Export(pStream, pNode, dwFlag, pChecksum);
    476 }
    477 
    478 bool CXFA_DataExporter::Export(const CFX_RetainPtr<IFGAS_Stream>& pStream,
    479                                CXFA_Node* pNode,
    480                                uint32_t dwFlag,
    481                                const FX_CHAR* pChecksum) {
    482   CFDE_XMLDoc* pXMLDoc = m_pDocument->GetXMLDoc();
    483   if (pNode->IsModelNode()) {
    484     switch (pNode->GetPacketID()) {
    485       case XFA_XDPPACKET_XDP: {
    486         static const FX_WCHAR s_pwsPreamble[] =
    487             L"<xdp:xdp xmlns:xdp=\"http://ns.adobe.com/xdp/\">";
    488         pStream->WriteString(s_pwsPreamble, FXSYS_wcslen(s_pwsPreamble));
    489         for (CXFA_Node* pChild = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    490              pChild; pChild = pChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
    491           Export(pStream, pChild, dwFlag, pChecksum);
    492         }
    493         static const FX_WCHAR s_pwsPostamble[] = L"</xdp:xdp\n>";
    494         pStream->WriteString(s_pwsPostamble, FXSYS_wcslen(s_pwsPostamble));
    495         break;
    496       }
    497       case XFA_XDPPACKET_Datasets: {
    498         CFDE_XMLElement* pElement =
    499             static_cast<CFDE_XMLElement*>(pNode->GetXMLMappingNode());
    500         if (!pElement || pElement->GetType() != FDE_XMLNODE_Element)
    501           return false;
    502 
    503         CXFA_Node* pDataNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    504         ASSERT(pDataNode);
    505         XFA_DataExporter_DealWithDataGroupNode(pDataNode);
    506         pXMLDoc->SaveXMLNode(pStream, pElement);
    507         break;
    508       }
    509       case XFA_XDPPACKET_Form: {
    510         XFA_DataExporter_RegenerateFormFile(pNode, pStream, pChecksum);
    511         break;
    512       }
    513       case XFA_XDPPACKET_Template:
    514       default: {
    515         CFDE_XMLElement* pElement =
    516             static_cast<CFDE_XMLElement*>(pNode->GetXMLMappingNode());
    517         if (!pElement || pElement->GetType() != FDE_XMLNODE_Element)
    518           return false;
    519 
    520         pXMLDoc->SaveXMLNode(pStream, pElement);
    521         break;
    522       }
    523     }
    524     return true;
    525   }
    526 
    527   CXFA_Node* pDataNode = pNode->GetNodeItem(XFA_NODEITEM_Parent);
    528   CXFA_Node* pExportNode = pNode;
    529   for (CXFA_Node* pChildNode = pDataNode->GetNodeItem(XFA_NODEITEM_FirstChild);
    530        pChildNode;
    531        pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling)) {
    532     if (pChildNode != pNode) {
    533       pExportNode = pDataNode;
    534       break;
    535     }
    536   }
    537   CFDE_XMLElement* pElement =
    538       static_cast<CFDE_XMLElement*>(pExportNode->GetXMLMappingNode());
    539   if (!pElement || pElement->GetType() != FDE_XMLNODE_Element)
    540     return false;
    541 
    542   XFA_DataExporter_DealWithDataGroupNode(pExportNode);
    543   pElement->SetString(L"xmlns:xfa", L"http://www.xfa.org/schema/xfa-data/1.0/");
    544   pXMLDoc->SaveXMLNode(pStream, pElement);
    545   pElement->RemoveAttribute(L"xmlns:xfa");
    546 
    547   return true;
    548 }
    549